This commit is contained in:
chiteroman 2024-01-22 23:01:38 +01:00
parent f4e0c5486c
commit 2ef939c1b8
8654 changed files with 987457 additions and 197 deletions

View File

@ -2,6 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/Dobby" vcs="Git" />
<mapping directory="$PROJECT_DIR$/app/src/main/cpp/libcxx" vcs="Git" />
</component>
</project>

View File

@ -8,31 +8,18 @@ android {
ndkVersion = "26.1.10909125"
buildToolsVersion = "34.0.0"
packaging {
jniLibs {
excludes += "**/liblog.so"
excludes += "**/libdobby.so"
}
}
defaultConfig {
applicationId = "es.chiteroman.playintegrityfix"
minSdk = 26
targetSdk = 34
versionCode = 15200
versionName = "v15.2"
versionCode = 15300
versionName = "v15.3"
externalNativeBuild {
cmake {
arguments += "-DANDROID_STL=none"
arguments += "-DCMAKE_BUILD_TYPE=MinSizeRel"
arguments += "-DPlugin.Android.BionicLinkerUtil=ON"
cppFlags += "-std=c++20"
cppFlags += "-fno-exceptions"
cppFlags += "-fno-rtti"
cppFlags += "-fvisibility=hidden"
cppFlags += "-fvisibility-inlines-hidden"
ndk {
abiFilters += "arm64-v8a"
abiFilters += "armeabi-v7a"
jobs = Runtime.getRuntime().availableProcessors()
}
}
}
@ -53,9 +40,8 @@ android {
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
ndkBuild {
path = file("src/main/cpp/Android.mk")
}
}
}

View File

@ -1,2 +1,3 @@
-keep class es.chiteroman.playintegrityfix.EntryPoint {public <methods>;}
-keep class es.chiteroman.playintegrityfix.CustomProvider
-keep class es.chiteroman.playintegrityfix.CustomKeyStoreSpi

View File

@ -0,0 +1,31 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := zygisk
LOCAL_SRC_FILES := $(LOCAL_PATH)/main.cpp
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/*.c)
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/common/*.c)
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/third_party/xdl/*.c)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/common
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/bsd
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/lss
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/third_party/xdl
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/arch/arm/*.c)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/arch/arm
else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
LOCAL_SRC_FILES += $(wildcard $(LOCAL_PATH)/shadowhook/arch/arm64/*.c)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/shadowhook/arch/arm64
endif
LOCAL_STATIC_LIBRARIES := libcxx
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
include $(LOCAL_PATH)/libcxx/Android.mk

View File

@ -0,0 +1,5 @@
APP_STL := none
APP_ABI := arm64-v8a armeabi-v7a
APP_CFLAGS := -Oz -flto -fvisibility=hidden -fvisibility-inlines-hidden
APP_CPPFLAGS := -std=c++20 -fno-exceptions -fno-rtti
APP_LDFLAGS := -Oz -flto

View File

@ -1,33 +0,0 @@
cmake_minimum_required(VERSION 3.22.1)
project("playintegrityfix")
include_directories(${CMAKE_SOURCE_DIR}/libcxx/include)
link_libraries(${CMAKE_SOURCE_DIR}/libcxx/${CMAKE_ANDROID_ARCH_ABI}/libcxx.a)
add_library(${CMAKE_PROJECT_NAME} SHARED
main.cpp)
if (NOT TARGET dobby)
set(DOBBY_DIR ${CMAKE_SOURCE_DIR}/Dobby)
macro(SET_OPTION option value)
set(${option} ${value} CACHE INTERNAL "" FORCE)
endmacro()
SET_OPTION(DOBBY_DEBUG OFF)
SET_OPTION(DOBBY_GENERATE_SHARED OFF)
SET_OPTION(Plugin.Android.BionicLinkerUtil ON)
add_subdirectory(${DOBBY_DIR} dobby)
get_property(DOBBY_INCLUDE_DIRECTORIES
TARGET dobby
PROPERTY INCLUDE_DIRECTORIES)
include_directories(
.
${DOBBY_INCLUDE_DIRECTORIES}
$<TARGET_PROPERTY:dobby,INCLUDE_DIRECTORIES>
)
endif ()
target_link_libraries(${CMAKE_PROJECT_NAME}
log
dobby)

@ -1 +0,0 @@
Subproject commit 6813ca76ddeafcaece525bf8c6cde7ff4c21d3ce

View File

@ -0,0 +1,88 @@
BasedOnStyle: LLVM
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: Consecutive
AlignEscapedNewlines: Right
AlignOperands: AlignAfterOperator
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortLambdasOnASingleLine: All
AttributeMacros: ['_LIBCPP_HIDE_FROM_ABI',
'_LIBCPP_CONSTEXPR',
'_LIBCPP_CONSTEXPR_SINCE_CXX14',
'_LIBCPP_CONSTEXPR_SINCE_CXX17',
'_LIBCPP_CONSTEXPR_SINCE_CXX20',
'_LIBCPP_CONSTEXPR_SINCE_CXX23',
'_LIBCPP_ALIGNOF',
'_ALIGNAS_TYPE',
'_ALIGNAS',
'_LIBCPP_NORETURN',
'_LIBCPP_ALWAYS_INLINE',
'_LIBCPP_DISABLE_EXTENTSION_WARNING',
'_LIBCPP_HIDDEN',
'_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS',
'_LIBCPP_FUNC_VIS',
'_LIBCPP_TYPE_VIS',
'_LIBCPP_TEMPLATE_VIS',
'_LIBCPP_TEMPLATE_DATA_VIS',
'_LIBCPP_EXPORTED_FROM_ABI',
'_LIBCPP_OVERRIDABLE_FUNC_VIS',
'_LIBCPP_EXCEPTION_ABI',
'_LIBCPP_ENUM_VIS',
'_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS',
'_LIBCPP_INTERNAL_LINKAGE',
'_LIBCPP_EXCLUDE_FROM_EXPLICIT_INSTANTIATION',
'_LIBCPP_HIDE_FROM_ABI_AFTER_V1',
'_LIBCPP_INLINE_VISIBILITY',
'_LIBCPP_CONSTEVAL',
'_LIBCPP_NOALIAS',
'_LIBCPP_USING_IF_EXISTS',
'_LIBCPP_DEPRECATED',
'_LIBCPP_DEPRECATED_IN_CXX11',
'_LIBCPP_DEPRECATED_IN_CXX14',
'_LIBCPP_DEPRECATED_IN_CXX17',
'_LIBCPP_DEPRECATED_IN_CXX20',
'_LIBCPP_NODISCARD',
'_LIBCPP_NODISCARD_EXT',
'_LIBCPP_NO_DESTROY',
'_LIBCPP_WEAK',
'_LIBCPP_CONSTINIT',
'_LIBCPP_FALLTHROUGH',
'_LIBCPP_STANDALONE_DEBUG',
'_LIBCPP_NO_UNIQUE_ADDRESS',
]
BinPackArguments: false
BinPackParameters: false
BreakBeforeConceptDeclarations: true
BreakInheritanceList: BeforeColon
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: Always
IndentWrappedFunctionNames: false
IndentRequires: true
InsertTrailingCommas: Wrapped
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
PackConstructorInitializers: NextLine
PenaltyIndentedWhitespace: 2
Language: Cpp
Standard: c++20
SpacesInAngles: Leave
AlwaysBreakTemplateDeclarations: true
PointerAlignment: Left
# Disable formatting options which may break tests.
SortIncludes: false
ReflowComments: false
# libc++'s preferred indentions of preprocessor statements.
IndentPPDirectives: AfterHash
# libc++ has some long names so we need more than the 80 column limit imposed by LLVM style, for sensible formatting
ColumnLimit: 120

View File

@ -0,0 +1,67 @@
Checks: >
bugprone-copy-constructor-init,
bugprone-dangling-handle,
bugprone-infinite-loop,
bugprone-stringview-nullptr,
bugprone-use-after-move,
llvm-include-order,
llvm-namespace-comment,
misc-definitions-in-headers,
misc-misplaced-const,
misc-non-copyable-objects,
misc-uniqueptr-reset-release,
modernize-loop-convert,
modernize-redundant-void-arg,
modernize-use-override,
readability-duplicate-include,
readability-identifier-naming,
readability-function-cognitive-complexity,
readability-function-size,
readability-misplaced-array-index,
readability-redundant-control-flow,
readability-redundant-function-ptr-dereference,
readability-redundant-preprocessor,
readability-simplify-boolean-expr,
readability-simplify-subscript-expr,
readability-uniqueptr-delete-release,
CheckOptions:
- key: readability-function-cognitive-complexity.Threshold
value: 143 # TODO: bring that number down
- key: readability-function-size.LineThreshold
value: 194 # TODO: bring that number down
- key: readability-identifier-naming.GetConfigPerFile
value: false
- key: readability-identifier-naming.ParameterCase
value: lower_case
- key: readability-identifier-naming.ParameterPrefix
value: __
- key: readability-identifier-naming.PrivateMemberCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberPrefix
value: __
- key: readability-identifier-naming.PrivateMemberSuffix
value: _
# TODO: investigate these checks
# bugprone-branch-clone,
# bugprone-macro-parentheses,
# cppcoreguidelines-prefer-member-initializer,
# misc-unused-parameters,
# modernize-use-bool-literals,
# modernize-use-default-member-init,
# modernize-use-equals-default,
# modernize-use-equals-delete,
# modernize-use-nullptr,
# portability-restrict-system-includes,
# readability-function-cognitive-complexity,
# readability-implicit-bool-conversion,
# readability-isolate-declaration,
# readability-redundant-access-specifiers,
# readability-redundant-declaration,
# readability-redundant-member-init,
#

55
app/src/main/cpp/libcxx/.gitignore vendored Normal file
View File

@ -0,0 +1,55 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
#lib/ # We actually have things checked in to lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# MSVC libraries test harness
env.lst
keep.lst
# Editor by-products
.vscode/

View File

@ -0,0 +1,114 @@
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.TXT for details.
LOCAL_PATH := $(call my-dir)
# libcxx defines
libcxx_includes := $(LOCAL_PATH)/include $(LOCAL_PATH)/src
libcxx_export_includes := $(libcxx_includes)
libcxx_sources := \
algorithm.cpp \
any.cpp \
atomic.cpp \
barrier.cpp \
bind.cpp \
charconv.cpp \
chrono.cpp \
condition_variable.cpp \
condition_variable_destructor.cpp \
debug.cpp \
exception.cpp \
filesystem/directory_iterator.cpp \
filesystem/int128_builtins.cpp \
filesystem/operations.cpp \
functional.cpp \
future.cpp \
hash.cpp \
ios.cpp \
ios.instantiations.cpp \
iostream.cpp \
legacy_debug_handler.cpp \
legacy_pointer_safety.cpp \
locale.cpp \
memory.cpp \
memory_resource.cpp \
mutex.cpp \
mutex_destructor.cpp \
new.cpp \
optional.cpp \
random_shuffle.cpp \
random.cpp \
regex.cpp \
shared_mutex.cpp \
stdexcept.cpp \
string.cpp \
strstream.cpp \
system_error.cpp \
thread.cpp \
typeinfo.cpp \
utility.cpp \
valarray.cpp \
variant.cpp \
vector.cpp \
verbose_abort.cpp \
libcxx_sources := $(libcxx_sources:%=src/%)
libcxx_export_cxxflags :=
libcxx_cxxflags := \
-std=c++20 \
-fvisibility-global-new-delete-hidden \
-fvisibility=hidden -fvisibility-inlines-hidden \
-DLIBCXX_BUILDING_LIBCXXABI \
-D_LIBCPP_NO_EXCEPTIONS \
-D_LIBCPP_NO_RTTI \
-D_LIBCPP_BUILDING_LIBRARY \
-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS \
-D__STDC_FORMAT_MACROS \
$(libcxx_export_cxxflags) \
libcxx_ldflags :=
libcxx_export_ldflags :=
# libcxxabi defines
libcxxabi_src_files := \
abort_message.cpp \
cxa_aux_runtime.cpp \
cxa_default_handlers.cpp \
cxa_exception_storage.cpp \
cxa_guard.cpp \
cxa_handlers.cpp \
cxa_noexception.cpp \
cxa_thread_atexit.cpp \
cxa_vector.cpp \
cxa_virtual.cpp \
stdlib_exception.cpp \
stdlib_new_delete.cpp \
stdlib_stdexcept.cpp \
stdlib_typeinfo.cpp \
libcxxabi_src_files := $(libcxxabi_src_files:%=src/abi/%)
libcxxabi_includes := \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/include/abi \
libcxxabi_cflags := -D__STDC_FORMAT_MACROS
libcxxabi_cppflags := \
-D_LIBCXXABI_NO_EXCEPTIONS \
-Wno-macro-redefined \
-Wno-unknown-attributes \
-DHAS_THREAD_LOCAL
include $(CLEAR_VARS)
LOCAL_MODULE := libcxx
LOCAL_SRC_FILES := $(libcxx_sources) $(libcxxabi_src_files)
LOCAL_C_INCLUDES := $(libcxx_includes) $(libcxxabi_includes)
LOCAL_CPPFLAGS := $(libcxx_cxxflags) $(libcxxabi_cppflags) -ffunction-sections -fdata-sections
LOCAL_EXPORT_C_INCLUDES := $(libcxx_export_includes)
LOCAL_EXPORT_CPPFLAGS := $(libcxx_export_cxxflags)
LOCAL_EXPORT_LDFLAGS := $(libcxx_export_ldflags)
include $(BUILD_STATIC_LIBRARY)

View File

@ -0,0 +1,937 @@
# See https://libcxx.llvm.org/docs/BuildingLibcxx.html for instructions on how
# to build libcxx with CMake.
#===============================================================================
# Setup Project
#===============================================================================
cmake_minimum_required(VERSION 3.13.4)
set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
# Add path for custom modules
list(INSERT CMAKE_MODULE_PATH 0
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
"${LLVM_COMMON_CMAKE_UTILS}"
"${LLVM_COMMON_CMAKE_UTILS}/Modules"
)
set(CMAKE_FOLDER "libc++")
set(LIBCXX_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LIBCXX_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(LIBCXX_BINARY_INCLUDE_DIR "${LIBCXX_BINARY_DIR}/include/c++build")
include(GNUInstallDirs)
# Require out of source build.
include(MacroEnsureOutOfSourceBuild)
MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
"${PROJECT_NAME} requires an out of source build. Please create a separate
build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there."
)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND "${CMAKE_CXX_SIMULATE_ID}" STREQUAL "MSVC")
message(STATUS "Configuring for clang-cl")
set(LIBCXX_TARGETING_CLANG_CL ON)
endif()
if (MSVC)
set(LIBCXX_TARGETING_MSVC ON)
message(STATUS "Configuring for MSVC")
else()
set(LIBCXX_TARGETING_MSVC OFF)
endif()
#===============================================================================
# Setup CMake Options
#===============================================================================
include(CMakeDependentOption)
include(HandleCompilerRT)
# Basic options ---------------------------------------------------------------
option(LIBCXX_ENABLE_ASSERTIONS
"Enable assertions inside the compiled library, and at the same time make it the
default when compiling user code. Note that assertions can be enabled or disabled
by users in their own code regardless of this option." OFF)
option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
set(ENABLE_FILESYSTEM_DEFAULT ON)
if (WIN32 AND NOT MINGW)
# Filesystem is buildable for windows, but it requires __int128 helper
# functions, that currently are provided by libgcc or compiler_rt builtins.
# These are available in MinGW environments, but not currently in MSVC
# environments.
set(ENABLE_FILESYSTEM_DEFAULT OFF)
endif()
option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of the main libc++ library"
${ENABLE_FILESYSTEM_DEFAULT})
option(LIBCXX_INCLUDE_TESTS "Build the libc++ tests." ${LLVM_INCLUDE_TESTS})
option(LIBCXX_ENABLE_PARALLEL_ALGORITHMS "Enable the parallel algorithms library. This requires the PSTL to be available." OFF)
option(LIBCXX_ENABLE_DEBUG_MODE
"Whether to build libc++ with the debug mode enabled.
By default, this is turned off. Turning it on results in a different ABI (additional
symbols but also potentially different layouts of types), and one should not mix code
built against a dylib that has debug mode and code built against a regular dylib." OFF)
option(LIBCXX_ENABLE_RANDOM_DEVICE
"Whether to include support for std::random_device in the library. Disabling
this can be useful when building the library for platforms that don't have
a source of randomness, such as some embedded platforms. When this is not
supported, most of <random> will still be available, but std::random_device
will not." ON)
option(LIBCXX_ENABLE_LOCALIZATION
"Whether to include support for localization in the library. Disabling
localization can be useful when porting to platforms that don't support
the C locale API (e.g. embedded). When localization is not supported,
several parts of the library will be disabled: <iostream>, <regex>, <locale>
will be completely unusable, and other parts may be only partly available." ON)
option(LIBCXX_ENABLE_UNICODE
"Whether to include support for Unicode in the library. Disabling Unicode can
be useful when porting to platforms that don't support UTF-8 encoding (e.g.
embedded)." ON)
option(LIBCXX_ENABLE_WIDE_CHARACTERS
"Whether to include support for wide characters in the library. Disabling
wide character support can be useful when porting to platforms that don't
support the C functionality for wide characters. When wide characters are
not supported, several parts of the library will be disabled, notably the
wide character specializations of std::basic_string." ON)
option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
"Whether to turn on vendor availability annotations on declarations that depend
on definitions in a shared library. By default, we assume that we're not building
libc++ for any specific vendor, and we disable those annotations. Vendors wishing
to provide compile-time errors when using features unavailable on some version of
the shared library they shipped should turn this on and see `include/__availability`
for more details." OFF)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
elseif(MINGW)
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-mingw.cfg.in")
elseif(WIN32) # clang-cl
if (LIBCXX_ENABLE_SHARED)
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-clangcl.cfg.in")
else()
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static-clangcl.cfg.in")
endif()
else()
if (LIBCXX_ENABLE_SHARED)
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared.cfg.in")
else()
set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static.cfg.in")
endif()
endif()
set(LIBCXX_TEST_CONFIG "${LIBCXX_DEFAULT_TEST_CONFIG}" CACHE STRING
"The path to the Lit testing configuration to use when running the tests.
If a relative path is provided, it is assumed to be relative to '<monorepo>/libcxx/test/configs'.")
if (NOT IS_ABSOLUTE "${LIBCXX_TEST_CONFIG}")
set(LIBCXX_TEST_CONFIG "${CMAKE_CURRENT_SOURCE_DIR}/test/configs/${LIBCXX_TEST_CONFIG}")
endif()
message(STATUS "Using libc++ testing configuration: ${LIBCXX_TEST_CONFIG}")
set(LIBCXX_TEST_PARAMS "" CACHE STRING
"A list of parameters to run the Lit test suite with.")
# Benchmark options -----------------------------------------------------------
option(LIBCXX_INCLUDE_BENCHMARKS "Build the libc++ benchmarks and their dependencies" ON)
set(LIBCXX_BENCHMARK_TEST_ARGS_DEFAULT --benchmark_min_time=0.01)
set(LIBCXX_BENCHMARK_TEST_ARGS "${LIBCXX_BENCHMARK_TEST_ARGS_DEFAULT}" CACHE STRING
"Arguments to pass when running the benchmarks using check-cxx-benchmarks")
set(LIBCXX_BENCHMARK_NATIVE_STDLIB "" CACHE STRING
"Build the benchmarks against the specified native STL.
The value must be one of libc++/libstdc++")
set(LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN "" CACHE STRING
"Use alternate GCC toolchain when building the native benchmarks")
if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
if (NOT (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libc++"
OR LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++"))
message(FATAL_ERROR "Invalid value for LIBCXX_BENCHMARK_NATIVE_STDLIB: "
"'${LIBCXX_BENCHMARK_NATIVE_STDLIB}'")
endif()
endif()
option(LIBCXX_INCLUDE_DOCS "Build the libc++ documentation." ${LLVM_INCLUDE_DOCS})
set(LIBCXX_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
"Define suffix of library directory name (32/64)")
option(LIBCXX_INSTALL_HEADERS "Install the libc++ headers." ON)
option(LIBCXX_INSTALL_LIBRARY "Install the libc++ library." ON)
cmake_dependent_option(LIBCXX_INSTALL_STATIC_LIBRARY
"Install the static libc++ library." ON
"LIBCXX_ENABLE_STATIC;LIBCXX_INSTALL_LIBRARY" OFF)
cmake_dependent_option(LIBCXX_INSTALL_SHARED_LIBRARY
"Install the shared libc++ library." ON
"LIBCXX_ENABLE_SHARED;LIBCXX_INSTALL_LIBRARY" OFF)
option(LIBCXX_ABI_UNSTABLE "Use the unstable ABI of libc++. This is equivalent to specifying LIBCXX_ABI_VERSION=n, where n is the not-yet-stable version." OFF)
if (LIBCXX_ABI_UNSTABLE)
set(abi_version "2")
else()
set(abi_version "1")
endif()
set(LIBCXX_ABI_VERSION "${abi_version}" CACHE STRING
"ABI version of libc++. Can be either 1 or 2, where 2 is currently the unstable ABI.
Defaults to 1 unless LIBCXX_ABI_UNSTABLE is specified, in which case this is 2.")
set(LIBCXX_LIBRARY_VERSION "${LIBCXX_ABI_VERSION}.0" CACHE STRING
"Version of libc++. This will be reflected in the name of the shared library produced.
For example, -DLIBCXX_LIBRARY_VERSION=x.y will result in the library being named
libc++.x.y.dylib, along with the usual symlinks pointing to that. On Apple platforms,
this also controls the linker's 'current_version' property.")
set(LIBCXX_ABI_NAMESPACE "__${LIBCXX_ABI_VERSION}" CACHE STRING "The inline ABI namespace used by libc++. It defaults to __n where `n` is the current ABI version.")
if (NOT LIBCXX_ABI_NAMESPACE MATCHES "__.*")
message(FATAL_ERROR "LIBCXX_ABI_NAMESPACE must be a reserved identifier, got '${LIBCXX_ABI_NAMESPACE}'.")
endif()
option(LIBCXX_ABI_FORCE_ITANIUM "Ignore auto-detection and force use of the Itanium ABI.")
option(LIBCXX_ABI_FORCE_MICROSOFT "Ignore auto-detection and force use of the Microsoft ABI.")
set(LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION "default" CACHE STRING
"Override the implementation to use for comparing typeinfos. By default, this
is detected automatically by the library, but this option allows overriding
which implementation is used unconditionally.
See the documentation in <libcxx/include/typeinfo> for details on what each
value means.")
set(TYPEINFO_COMPARISON_VALUES "default;1;2;3")
if (NOT ("${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}" IN_LIST TYPEINFO_COMPARISON_VALUES))
message(FATAL_ERROR "Value '${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}' is not a valid value for
LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION")
endif()
set(LIBCXX_ABI_DEFINES "" CACHE STRING "A semicolon separated list of ABI macros to define in the site config header.")
option(LIBCXX_EXTRA_SITE_DEFINES "Extra defines to add into __config_site")
option(LIBCXX_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
option(LIBCXX_ENABLE_BACKWARDS_COMPATIBILITY_DEBUG_MODE_SYMBOLS
"Whether to include the old Debug mode symbols in the compiled library. This
is provided for backwards compatibility since the compiled library used to
always contain those symbols, regardless of whether the library was built
with the debug mode enabled. This is OFF by default, please contact the libc++
developers if you need to turn this on, as this will be removed in LLVM 16." OFF)
# ABI Library options ---------------------------------------------------------
if (LIBCXX_TARGETING_MSVC)
set(LIBCXX_DEFAULT_ABI_LIBRARY "vcruntime")
elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
set(LIBCXX_DEFAULT_ABI_LIBRARY "libcxxrt")
else()
set(LIBCXX_DEFAULT_ABI_LIBRARY "libcxxabi")
endif()
set(LIBCXX_SUPPORTED_ABI_LIBRARIES none libcxxabi system-libcxxabi libcxxrt libstdc++ libsupc++ vcruntime)
set(LIBCXX_CXX_ABI "${LIBCXX_DEFAULT_ABI_LIBRARY}" CACHE STRING "Specify C++ ABI library to use. Supported values are ${LIBCXX_SUPPORTED_ABI_LIBRARIES}.")
if (NOT "${LIBCXX_CXX_ABI}" IN_LIST LIBCXX_SUPPORTED_ABI_LIBRARIES)
message(FATAL_ERROR "Unsupported C++ ABI library: '${LIBCXX_CXX_ABI}'. Supported values are ${LIBCXX_SUPPORTED_ABI_LIBRARIES}.")
endif()
option(LIBCXX_ENABLE_STATIC_ABI_LIBRARY
"Use a static copy of the ABI library when linking libc++.
This option cannot be used with LIBCXX_ENABLE_ABI_LINKER_SCRIPT." OFF)
cmake_dependent_option(LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY
"Statically link the ABI library to static library" ON
"LIBCXX_ENABLE_STATIC_ABI_LIBRARY" OFF)
cmake_dependent_option(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY
"Statically link the ABI library to shared library" ON
"LIBCXX_ENABLE_STATIC_ABI_LIBRARY" OFF)
# Generate and install a linker script inplace of libc++.so. The linker script
# will link libc++ to the correct ABI library. This option is on by default
# on UNIX platforms other than Apple unless 'LIBCXX_ENABLE_STATIC_ABI_LIBRARY'
# is on. This option is also disabled when the ABI library is not specified
# or is specified to be "none".
set(ENABLE_LINKER_SCRIPT_DEFAULT_VALUE OFF)
if (LLVM_HAVE_LINK_VERSION_SCRIPT AND NOT LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY
AND NOT LIBCXX_CXX_ABI STREQUAL "none"
AND Python3_EXECUTABLE
AND LIBCXX_ENABLE_SHARED)
set(ENABLE_LINKER_SCRIPT_DEFAULT_VALUE ON)
endif()
option(LIBCXX_ENABLE_ABI_LINKER_SCRIPT
"Use and install a linker script for the given ABI library"
${ENABLE_LINKER_SCRIPT_DEFAULT_VALUE})
option(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS
"Build libc++ with definitions for operator new/delete. These are normally
defined in libc++abi, but this option can be used to define them in libc++
instead. If you define them in libc++, make sure they are NOT defined in
libc++abi. Doing otherwise is an ODR violation." OFF)
# Build libc++abi with libunwind. We need this option to determine whether to
# link with libunwind or libgcc_s while running the test cases.
option(LIBCXXABI_USE_LLVM_UNWINDER "Build and use the LLVM unwinder." OFF)
# Target options --------------------------------------------------------------
option(LIBCXX_BUILD_32_BITS "Build 32 bit multilib libc++. This option is not supported anymore when building the runtimes. Please specify a full triple instead." ${LLVM_BUILD_32_BITS})
if (LIBCXX_BUILD_32_BITS)
message(FATAL_ERROR "LIBCXX_BUILD_32_BITS is not supported anymore when building the runtimes, please specify a full triple instead.")
endif()
# TODO: Remove this after branching for LLVM 15
if(LIBCXX_SYSROOT OR LIBCXX_TARGET_TRIPLE OR LIBCXX_GCC_TOOLCHAIN)
message(WARNING "LIBCXX_SYSROOT, LIBCXX_TARGET_TRIPLE and LIBCXX_GCC_TOOLCHAIN are not supported anymore, please use the native CMake equivalents instead")
endif()
# Feature options -------------------------------------------------------------
option(LIBCXX_ENABLE_EXCEPTIONS "Use exceptions." ON)
option(LIBCXX_ENABLE_RTTI "Use run time type information." ON)
option(LIBCXX_ENABLE_THREADS "Build libc++ with support for threads." ON)
option(LIBCXX_ENABLE_MONOTONIC_CLOCK
"Build libc++ with support for a monotonic clock.
This option may only be set to OFF when LIBCXX_ENABLE_THREADS=OFF." ON)
option(LIBCXX_HAS_MUSL_LIBC "Build libc++ with support for the Musl C library" OFF)
option(LIBCXX_HAS_PTHREAD_API "Ignore auto-detection and force use of pthread API" OFF)
option(LIBCXX_HAS_WIN32_THREAD_API "Ignore auto-detection and force use of win32 thread API" OFF)
option(LIBCXX_HAS_EXTERNAL_THREAD_API
"Build libc++ with an externalized threading API.
This option may only be set to ON when LIBCXX_ENABLE_THREADS=ON." OFF)
option(LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY
"Build libc++ with an externalized threading library.
This option may only be set to ON when LIBCXX_ENABLE_THREADS=ON" OFF)
# Misc options ----------------------------------------------------------------
# FIXME: Turn -pedantic back ON. It is currently off because it warns
# about #include_next which is used everywhere.
option(LIBCXX_ENABLE_PEDANTIC "Compile with pedantic enabled." OFF)
option(LIBCXX_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
option(LIBCXX_DISABLE_MACRO_CONFLICT_WARNINGS "Disable #warnings about conflicting macros." OFF)
option(LIBCXX_GENERATE_COVERAGE "Enable generating code coverage." OFF)
set(LIBCXX_COVERAGE_LIBRARY "" CACHE STRING
"The Profile-rt library used to build with code coverage")
set(LIBCXX_CONFIGURE_IDE_DEFAULT OFF)
if (XCODE OR MSVC_IDE)
set(LIBCXX_CONFIGURE_IDE_DEFAULT ON)
endif()
option(LIBCXX_CONFIGURE_IDE "Configure libcxx for use within an IDE"
${LIBCXX_CONFIGURE_IDE_DEFAULT})
set(LIBCXX_HERMETIC_STATIC_LIBRARY_DEFAULT OFF)
if (WIN32)
set(LIBCXX_HERMETIC_STATIC_LIBRARY_DEFAULT ON)
endif()
option(LIBCXX_HERMETIC_STATIC_LIBRARY
"Do not export any symbols from the static library." ${LIBCXX_HERMETIC_STATIC_LIBRARY_DEFAULT})
#===============================================================================
# Check option configurations
#===============================================================================
# Ensure LIBCXX_ENABLE_MONOTONIC_CLOCK is set to ON only when
# LIBCXX_ENABLE_THREADS is on.
if(LIBCXX_ENABLE_THREADS AND NOT LIBCXX_ENABLE_MONOTONIC_CLOCK)
message(FATAL_ERROR "LIBCXX_ENABLE_MONOTONIC_CLOCK can only be set to OFF"
" when LIBCXX_ENABLE_THREADS is also set to OFF.")
endif()
if(NOT LIBCXX_ENABLE_THREADS)
if(LIBCXX_HAS_PTHREAD_API)
message(FATAL_ERROR "LIBCXX_HAS_PTHREAD_API can only be set to ON"
" when LIBCXX_ENABLE_THREADS is also set to ON.")
endif()
if(LIBCXX_HAS_EXTERNAL_THREAD_API)
message(FATAL_ERROR "LIBCXX_HAS_EXTERNAL_THREAD_API can only be set to ON"
" when LIBCXX_ENABLE_THREADS is also set to ON.")
endif()
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY)
message(FATAL_ERROR "LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY can only be set "
"to ON when LIBCXX_ENABLE_THREADS is also set to ON.")
endif()
if (LIBCXX_HAS_WIN32_THREAD_API)
message(FATAL_ERROR "LIBCXX_HAS_WIN32_THREAD_API can only be set to ON"
" when LIBCXX_ENABLE_THREADS is also set to ON.")
endif()
endif()
if (LIBCXX_HAS_EXTERNAL_THREAD_API)
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY)
message(FATAL_ERROR "The options LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY and "
"LIBCXX_HAS_EXTERNAL_THREAD_API cannot both be ON at "
"the same time")
endif()
if (LIBCXX_HAS_PTHREAD_API)
message(FATAL_ERROR "The options LIBCXX_HAS_EXTERNAL_THREAD_API"
"and LIBCXX_HAS_PTHREAD_API cannot be both"
"set to ON at the same time.")
endif()
if (LIBCXX_HAS_WIN32_THREAD_API)
message(FATAL_ERROR "The options LIBCXX_HAS_EXTERNAL_THREAD_API"
"and LIBCXX_HAS_WIN32_THREAD_API cannot be both"
"set to ON at the same time.")
endif()
endif()
if (LIBCXX_HAS_PTHREAD_API)
if (LIBCXX_HAS_WIN32_THREAD_API)
message(FATAL_ERROR "The options LIBCXX_HAS_PTHREAD_API"
"and LIBCXX_HAS_WIN32_THREAD_API cannot be both"
"set to ON at the same time.")
endif()
endif()
# Ensure LLVM_USE_SANITIZER is not specified when LIBCXX_GENERATE_COVERAGE
# is ON.
if (LLVM_USE_SANITIZER AND LIBCXX_GENERATE_COVERAGE)
message(FATAL_ERROR "LLVM_USE_SANITIZER cannot be used with LIBCXX_GENERATE_COVERAGE")
endif()
# Warn users that LIBCXX_ENABLE_STATIC_ABI_LIBRARY is an experimental option.
if (LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
message(WARNING "LIBCXX_ENABLE_STATIC_ABI_LIBRARY is an experimental option")
if (LIBCXX_ENABLE_STATIC AND NOT Python3_EXECUTABLE)
message(FATAL_ERROR "LIBCXX_ENABLE_STATIC_ABI_LIBRARY requires python but it was not found.")
endif()
endif()
if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
if (APPLE)
message(FATAL_ERROR "LIBCXX_ENABLE_ABI_LINKER_SCRIPT cannot be used on APPLE targets")
endif()
if (NOT LIBCXX_ENABLE_SHARED)
message(FATAL_ERROR "LIBCXX_ENABLE_ABI_LINKER_SCRIPT is only available for shared library builds.")
endif()
endif()
if (LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY AND LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
message(FATAL_ERROR "Conflicting options given.
LIBCXX_ENABLE_STATIC_ABI_LIBRARY cannot be specified with
LIBCXX_ENABLE_ABI_LINKER_SCRIPT")
endif()
if (LIBCXX_ABI_FORCE_ITANIUM AND LIBCXX_ABI_FORCE_MICROSOFT)
message(FATAL_ERROR "Only one of LIBCXX_ABI_FORCE_ITANIUM and LIBCXX_ABI_FORCE_MICROSOFT can be specified.")
endif ()
#===============================================================================
# Configure System
#===============================================================================
# TODO: Projects that depend on libc++ should use LIBCXX_GENERATED_INCLUDE_DIR
# instead of hard-coding include/c++/v1.
set(LIBCXX_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}/c++/v1" CACHE PATH
"Path where target-agnostic libc++ headers should be installed.")
set(LIBCXX_INSTALL_RUNTIME_DIR "${CMAKE_INSTALL_BINDIR}" CACHE PATH
"Path where built libc++ runtime libraries should be installed.")
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR}/${LLVM_DEFAULT_TARGET_TRIPLE})
set(LIBCXX_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1")
set(LIBCXX_GENERATED_INCLUDE_TARGET_DIR "${LLVM_BINARY_DIR}/include/${LLVM_DEFAULT_TARGET_TRIPLE}/c++/v1")
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LLVM_LIBDIR_SUFFIX}/${LLVM_DEFAULT_TARGET_TRIPLE} CACHE PATH
"Path where built libc++ libraries should be installed.")
set(LIBCXX_INSTALL_INCLUDE_TARGET_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${LLVM_DEFAULT_TARGET_TRIPLE}/c++/v1" CACHE PATH
"Path where target-specific libc++ headers should be installed.")
if(LIBCXX_LIBDIR_SUBDIR)
string(APPEND LIBCXX_LIBRARY_DIR /${LIBCXX_LIBDIR_SUBDIR})
string(APPEND LIBCXX_INSTALL_LIBRARY_DIR /${LIBCXX_LIBDIR_SUBDIR})
endif()
else()
if(LLVM_LIBRARY_OUTPUT_INTDIR)
set(LIBCXX_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
set(LIBCXX_GENERATED_INCLUDE_DIR "${LLVM_BINARY_DIR}/include/c++/v1")
else()
set(LIBCXX_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBCXX_LIBDIR_SUFFIX})
set(LIBCXX_GENERATED_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include/c++/v1")
endif()
set(LIBCXX_GENERATED_INCLUDE_TARGET_DIR "${LIBCXX_GENERATED_INCLUDE_DIR}")
set(LIBCXX_INSTALL_LIBRARY_DIR lib${LIBCXX_LIBDIR_SUFFIX} CACHE PATH
"Path where built libc++ libraries should be installed.")
set(LIBCXX_INSTALL_INCLUDE_TARGET_DIR "${LIBCXX_INSTALL_INCLUDE_DIR}" CACHE PATH
"Path where target-specific libc++ headers should be installed.")
endif()
file(MAKE_DIRECTORY "${LIBCXX_BINARY_INCLUDE_DIR}")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBCXX_LIBRARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBCXX_LIBRARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBCXX_LIBRARY_DIR})
# Declare libc++ configuration variables.
# They are intended for use as follows:
# LIBCXX_CXX_FLAGS: General flags for both the compiler and linker.
# LIBCXX_COMPILE_FLAGS: Compile only flags.
# LIBCXX_LINK_FLAGS: Linker only flags.
# LIBCXX_LIBRARIES: libraries libc++ is linked to.
set(LIBCXX_COMPILE_FLAGS "")
set(LIBCXX_LINK_FLAGS "")
set(LIBCXX_LIBRARIES "")
# Include macros for adding and removing libc++ flags.
include(HandleLibcxxFlags)
# Target flags ================================================================
# These flags get added to CMAKE_CXX_FLAGS and CMAKE_C_FLAGS so that
# 'config-ix' use them during feature checks. It also adds them to both
# 'LIBCXX_COMPILE_FLAGS' and 'LIBCXX_LINK_FLAGS'
if(ZOS)
add_target_flags_if_supported("-fzos-le-char-mode=ebcdic")
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "AIX")
add_target_flags_if_supported("-mdefault-visibility-export-mapping=explicit")
set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
endif()
# Configure compiler.
include(config-ix)
# Configure coverage options.
if (LIBCXX_GENERATE_COVERAGE)
include(CodeCoverage)
set(CMAKE_BUILD_TYPE "COVERAGE" CACHE STRING "" FORCE)
endif()
string(TOUPPER "${CMAKE_BUILD_TYPE}" uppercase_CMAKE_BUILD_TYPE)
if (uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
set(LIBCXX_DEBUG_BUILD ON)
else()
set(LIBCXX_DEBUG_BUILD OFF)
endif()
#===============================================================================
# Setup Compiler Flags
#===============================================================================
include(HandleLibCXXABI) # Setup the ABI library flags
# Remove flags that may have snuck in.
# TODO: This shouldn't be necessary anymore since we don't support the Project
# build anymore, so the rest of LLVM can't pollute our flags.
remove_flags(-DNDEBUG -UNDEBUG -D_DEBUG -lc++abi)
remove_flags(--stdlib=libc++ -stdlib=libc++ --stdlib=libstdc++ -stdlib=libstdc++)
# FIXME: Remove all debug flags and flags that change which Windows
# default libraries are linked. Currently we only support linking the
# non-debug DLLs
remove_flags("/D_DEBUG" "/MTd" "/MDd" "/MT" "/Md")
# FIXME(EricWF): See the FIXME on LIBCXX_ENABLE_PEDANTIC.
# Remove the -pedantic flag and -Wno-pedantic and -pedantic-errors
# so they don't get transformed into -Wno and -errors respectively.
remove_flags(-Wno-pedantic -pedantic-errors -pedantic)
# Required flags ==============================================================
function(cxx_add_basic_build_flags target)
# Require C++20 for all targets. C++17 is needed to use aligned allocation
# in the dylib. C++20 is needed to use char8_t.
set_target_properties(${target} PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO)
# When building the dylib, don't warn for unavailable aligned allocation
# functions based on the deployment target -- they are always available
# because they are provided by the dylib itself with the excepton of z/OS.
if (ZOS)
target_add_compile_flags_if_supported(${target} PRIVATE -fno-aligned-allocation)
else()
target_add_compile_flags_if_supported(${target} PRIVATE -faligned-allocation)
endif()
# On all systems the system c++ standard library headers need to be excluded.
# MSVC only has -X, which disables all default includes; including the crt.
# Thus, we do nothing and hope we don't accidentally include any of the C++
# headers
target_add_compile_flags_if_supported(${target} PUBLIC -nostdinc++)
# Hide all inline function definitions which have not explicitly been marked
# visible. This prevents new definitions for inline functions from appearing in
# the dylib when get ODR used by another function.
target_add_compile_flags_if_supported(${target} PRIVATE -fvisibility-inlines-hidden)
# Our visibility annotations are not quite right for non-Clang compilers,
# so we end up not exporting all the symbols we should. In the future, we
# can improve the situation by providing an explicit list of exported
# symbols on all compilers.
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
target_add_compile_flags_if_supported(${target} PRIVATE -fvisibility=hidden)
endif()
if (LIBCXX_CONFIGURE_IDE)
# This simply allows IDE to process <experimental/coroutine>
target_add_compile_flags_if_supported(${target} PRIVATE -fcoroutines-ts)
endif()
# Let the library headers know they are currently being used to build the
# library.
target_compile_definitions(${target} PRIVATE -D_LIBCPP_BUILDING_LIBRARY)
if (NOT LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS)
target_compile_definitions(${target} PRIVATE -D_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS)
endif()
if (C_SUPPORTS_COMMENT_LIB_PRAGMA)
if (LIBCXX_HAS_PTHREAD_LIB)
target_compile_definitions(${target} PRIVATE -D_LIBCPP_LINK_PTHREAD_LIB)
endif()
if (LIBCXX_HAS_RT_LIB)
target_compile_definitions(${target} PRIVATE -D_LIBCPP_LINK_RT_LIB)
endif()
endif()
endfunction()
# Warning flags ===============================================================
function(cxx_add_warning_flags target)
target_compile_definitions(${target} PUBLIC -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
if (MSVC)
# -W4 is the cl.exe/clang-cl equivalent of -Wall. (In cl.exe and clang-cl,
# -Wall is equivalent to -Weverything in GCC style compiler drivers.)
target_add_compile_flags_if_supported(${target} PRIVATE -W4)
else()
target_add_compile_flags_if_supported(${target} PRIVATE -Wall)
endif()
target_add_compile_flags_if_supported(${target} PRIVATE -Wextra -W -Wwrite-strings
-Wno-unused-parameter -Wno-long-long
-Werror=return-type -Wextra-semi -Wundef
-Wformat-nonliteral)
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
target_add_compile_flags_if_supported(${target} PRIVATE
-Wno-user-defined-literals
-Wno-covered-switch-default
-Wno-suggest-override
)
if (LIBCXX_TARGETING_CLANG_CL)
target_add_compile_flags_if_supported(${target} PRIVATE
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
-Wno-c++11-compat
-Wno-undef
-Wno-reserved-id-macro
-Wno-gnu-include-next
-Wno-gcc-compat # For ignoring "'diagnose_if' is a clang extension" warnings
-Wno-zero-as-null-pointer-constant # FIXME: Remove this and fix all occurrences.
-Wno-deprecated-dynamic-exception-spec # For auto_ptr
-Wno-sign-conversion
-Wno-old-style-cast
-Wno-deprecated # FIXME: Remove this and fix all occurrences.
-Wno-shift-sign-overflow # FIXME: Why do we need this with clang-cl but not clang?
-Wno-double-promotion # FIXME: remove me
)
endif()
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
target_add_compile_flags_if_supported(${target} PRIVATE
-Wno-attributes
-Wno-literal-suffix
-Wno-c++14-compat
-Wno-noexcept-type
-Wno-suggest-override)
endif()
if (LIBCXX_ENABLE_WERROR)
target_add_compile_flags_if_supported(${target} PRIVATE -Werror)
target_add_compile_flags_if_supported(${target} PRIVATE -WX)
else()
# TODO(EricWF) Remove this. We shouldn't be suppressing errors when -Werror is
# added elsewhere.
target_add_compile_flags_if_supported(${target} PRIVATE -Wno-error)
endif()
if (LIBCXX_ENABLE_PEDANTIC)
target_add_compile_flags_if_supported(${target} PRIVATE -pedantic)
endif()
endfunction()
# Exception flags =============================================================
function(cxx_add_exception_flags target)
if (LIBCXX_ENABLE_EXCEPTIONS)
# Catches C++ exceptions only and tells the compiler to assume that extern C
# functions never throw a C++ exception.
target_add_compile_flags_if_supported(${target} PUBLIC -EHsc)
else()
target_add_compile_flags_if_supported(${target} PUBLIC -EHs- -EHa-)
target_add_compile_flags_if_supported(${target} PUBLIC -fno-exceptions)
endif()
endfunction()
# RTTI flags ==================================================================
function(cxx_add_rtti_flags target)
if (NOT LIBCXX_ENABLE_RTTI)
target_add_compile_flags_if_supported(${target} PUBLIC -GR-)
target_add_compile_flags_if_supported(${target} PUBLIC -fno-rtti)
endif()
endfunction()
# Threading flags =============================================================
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY AND LIBCXX_ENABLE_SHARED)
# Need to allow unresolved symbols if this is to work with shared library builds
if (APPLE)
add_link_flags("-undefined dynamic_lookup")
else()
# Relax this restriction from HandleLLVMOptions
string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
endif()
endif()
# Assertion flags =============================================================
define_if(LIBCXX_DEBUG_BUILD -D_DEBUG)
if (LIBCXX_ENABLE_ASSERTIONS AND NOT LIBCXX_DEBUG_BUILD)
# MSVC doesn't like _DEBUG on release builds. See PR 4379.
define_if_not(LIBCXX_TARGETING_MSVC -D_DEBUG)
endif()
# Modules flags ===============================================================
# FIXME The libc++ sources are fundamentally non-modular. They need special
# versions of the headers in order to provide C++03 and legacy ABI definitions.
# NOTE: The public headers can be used with modules in all other contexts.
function(cxx_add_module_flags target)
if (LLVM_ENABLE_MODULES)
# Ignore that the rest of the modules flags are now unused.
target_add_compile_flags_if_supported(${target} PUBLIC -Wno-unused-command-line-argument)
target_compile_options(${target} PUBLIC -fno-modules)
endif()
endfunction()
# Sanitizer flags =============================================================
function(get_sanitizer_flags OUT_VAR USE_SANITIZER)
set(SANITIZER_FLAGS)
set(USE_SANITIZER "${USE_SANITIZER}")
# NOTE: LLVM_USE_SANITIZER checks for a UNIX like system instead of MSVC.
# But we don't have LLVM_ON_UNIX so checking for MSVC is the best we can do.
if (USE_SANITIZER AND NOT MSVC)
append_flags_if_supported(SANITIZER_FLAGS "-fno-omit-frame-pointer")
append_flags_if_supported(SANITIZER_FLAGS "-gline-tables-only")
if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" AND
NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO")
append_flags_if_supported(SANITIZER_FLAGS "-gline-tables-only")
endif()
if (USE_SANITIZER STREQUAL "Address")
append_flags(SANITIZER_FLAGS "-fsanitize=address")
elseif (USE_SANITIZER MATCHES "Memory(WithOrigins)?")
append_flags(SANITIZER_FLAGS -fsanitize=memory)
if (USE_SANITIZER STREQUAL "MemoryWithOrigins")
append_flags(SANITIZER_FLAGS "-fsanitize-memory-track-origins")
endif()
elseif (USE_SANITIZER STREQUAL "Undefined")
append_flags(SANITIZER_FLAGS "-fsanitize=undefined -fno-sanitize=vptr,function -fno-sanitize-recover=all")
elseif (USE_SANITIZER STREQUAL "Address;Undefined" OR
USE_SANITIZER STREQUAL "Undefined;Address")
append_flags(SANITIZER_FLAGS "-fsanitize=address,undefined -fno-sanitize=vptr,function -fno-sanitize-recover=all")
elseif (USE_SANITIZER STREQUAL "Thread")
append_flags(SANITIZER_FLAGS -fsanitize=thread)
elseif (USE_SANITIZER STREQUAL "DataFlow")
append_flags(SANITIZER_FLAGS -fsanitize=dataflow)
else()
message(WARNING "Unsupported value of LLVM_USE_SANITIZER: ${USE_SANITIZER}")
endif()
elseif(USE_SANITIZER AND MSVC)
message(WARNING "LLVM_USE_SANITIZER is not supported on this platform.")
endif()
set(${OUT_VAR} "${SANITIZER_FLAGS}" PARENT_SCOPE)
endfunction()
get_sanitizer_flags(SANITIZER_FLAGS "${LLVM_USE_SANITIZER}")
# Link system libraries =======================================================
function(cxx_link_system_libraries target)
# In order to remove just libc++ from the link step
# we need to use -nostdlib++ whenever it is supported.
# Unfortunately this cannot be used universally because for example g++ supports
# only -nodefaultlibs in which case all libraries will be removed and
# all libraries but c++ have to be added in manually.
if (CXX_SUPPORTS_NOSTDLIBXX_FLAG)
target_add_link_flags_if_supported(${target} PRIVATE "-nostdlib++")
else()
target_add_link_flags_if_supported(${target} PRIVATE "-nodefaultlibs")
target_add_compile_flags_if_supported(${target} PRIVATE "/Zl")
target_add_link_flags_if_supported(${target} PRIVATE "/nodefaultlib")
endif()
if (CXX_SUPPORTS_UNWINDLIB_EQ_NONE_FLAG AND LIBCXXABI_USE_LLVM_UNWINDER)
# If we're linking directly against the libunwind that we're building
# in the same invocation, don't try to link in the toolchain's
# default libunwind (which may be missing still).
target_add_link_flags_if_supported(${target} PRIVATE "--unwindlib=none")
endif()
if (LIBCXX_HAS_SYSTEM_LIB)
target_link_libraries(${target} PRIVATE System)
endif()
if (LIBCXX_HAS_PTHREAD_LIB)
target_link_libraries(${target} PRIVATE pthread)
endif()
if (LIBCXX_HAS_C_LIB)
target_link_libraries(${target} PRIVATE c)
endif()
if (LIBCXX_HAS_M_LIB)
target_link_libraries(${target} PRIVATE m)
endif()
if (LIBCXX_HAS_RT_LIB)
target_link_libraries(${target} PRIVATE rt)
endif()
if (LIBCXX_USE_COMPILER_RT)
find_compiler_rt_library(builtins LIBCXX_BUILTINS_LIBRARY)
if (LIBCXX_BUILTINS_LIBRARY)
target_link_libraries(${target} PRIVATE "${LIBCXX_BUILTINS_LIBRARY}")
endif()
elseif (LIBCXX_HAS_GCC_LIB)
target_link_libraries(${target} PRIVATE gcc)
elseif (LIBCXX_HAS_GCC_S_LIB)
target_link_libraries(${target} PRIVATE gcc_s)
endif()
if (LIBCXX_HAS_ATOMIC_LIB)
target_link_libraries(${target} PRIVATE atomic)
endif()
if (MINGW)
target_link_libraries(${target} PRIVATE "${MINGW_LIBRARIES}")
endif()
if (LIBCXX_TARGETING_MSVC)
if (LIBCXX_DEBUG_BUILD)
set(LIB_SUFFIX "d")
else()
set(LIB_SUFFIX "")
endif()
target_link_libraries(${target} PRIVATE ucrt${LIB_SUFFIX}) # Universal C runtime
target_link_libraries(${target} PRIVATE vcruntime${LIB_SUFFIX}) # C++ runtime
target_link_libraries(${target} PRIVATE msvcrt${LIB_SUFFIX}) # C runtime startup files
target_link_libraries(${target} PRIVATE msvcprt${LIB_SUFFIX}) # C++ standard library. Required for exception_ptr internals.
# Required for standards-complaint wide character formatting functions
# (e.g. `printfw`/`scanfw`)
target_link_libraries(${target} PRIVATE iso_stdio_wide_specifiers)
endif()
if (ANDROID AND ANDROID_PLATFORM_LEVEL LESS 21)
target_link_libraries(${target} PUBLIC android_support)
endif()
endfunction()
# Windows-related flags =======================================================
function(cxx_add_windows_flags target)
if(WIN32 AND NOT MINGW)
target_compile_definitions(${target} PRIVATE
# Ignore the -MSC_VER mismatch, as we may build
# with a different compatibility version.
_ALLOW_MSC_VER_MISMATCH
# Don't check the msvcprt iterator debug levels
# as we will define the iterator types; libc++
# uses a different macro to identify the debug
# level.
_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH
# We are building the c++ runtime, don't pull in
# msvcprt.
_CRTBLD
# Don't warn on the use of "deprecated"
# "insecure" functions which are standards
# specified.
_CRT_SECURE_NO_WARNINGS
# Use the ISO conforming behaviour for conversion
# in printf, scanf.
_CRT_STDIO_ISO_WIDE_SPECIFIERS)
endif()
endfunction()
# Configuration file flags =====================================================
config_define(${LIBCXX_ABI_VERSION} _LIBCPP_ABI_VERSION)
config_define(${LIBCXX_ABI_NAMESPACE} _LIBCPP_ABI_NAMESPACE)
config_define_if(LIBCXX_ABI_FORCE_ITANIUM _LIBCPP_ABI_FORCE_ITANIUM)
config_define_if(LIBCXX_ABI_FORCE_MICROSOFT _LIBCPP_ABI_FORCE_MICROSOFT)
config_define_if_not(LIBCXX_ENABLE_THREADS _LIBCPP_HAS_NO_THREADS)
config_define_if_not(LIBCXX_ENABLE_MONOTONIC_CLOCK _LIBCPP_HAS_NO_MONOTONIC_CLOCK)
if (NOT LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION STREQUAL "default")
config_define("${LIBCXX_TYPEINFO_COMPARISON_IMPLEMENTATION}" _LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION)
endif()
config_define_if(LIBCXX_HAS_PTHREAD_API _LIBCPP_HAS_THREAD_API_PTHREAD)
config_define_if(LIBCXX_HAS_EXTERNAL_THREAD_API _LIBCPP_HAS_THREAD_API_EXTERNAL)
config_define_if(LIBCXX_HAS_WIN32_THREAD_API _LIBCPP_HAS_THREAD_API_WIN32)
config_define_if(LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL)
config_define_if(LIBCXX_HAS_MUSL_LIBC _LIBCPP_HAS_MUSL_LIBC)
config_define_if(LIBCXX_NO_VCRUNTIME _LIBCPP_NO_VCRUNTIME)
config_define_if(LIBCXX_ENABLE_PARALLEL_ALGORITHMS _LIBCPP_HAS_PARALLEL_ALGORITHMS)
config_define_if_not(LIBCXX_ENABLE_FILESYSTEM _LIBCPP_HAS_NO_FILESYSTEM_LIBRARY)
config_define_if_not(LIBCXX_ENABLE_RANDOM_DEVICE _LIBCPP_HAS_NO_RANDOM_DEVICE)
config_define_if_not(LIBCXX_ENABLE_LOCALIZATION _LIBCPP_HAS_NO_LOCALIZATION)
config_define_if_not(LIBCXX_ENABLE_UNICODE _LIBCPP_HAS_NO_UNICODE)
config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTERS)
config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
config_define_if(LIBCXX_ENABLE_DEBUG_MODE _LIBCPP_ENABLE_DEBUG_MODE)
if (LIBCXX_ENABLE_ASSERTIONS)
config_define(1 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT)
else()
config_define(0 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT)
endif()
if (LIBCXX_ABI_DEFINES)
set(abi_defines)
foreach (abi_define ${LIBCXX_ABI_DEFINES})
if (NOT abi_define MATCHES "^_LIBCPP_ABI_")
message(SEND_ERROR "Invalid ABI macro ${abi_define} in LIBCXX_ABI_DEFINES")
endif()
list(APPEND abi_defines "#define ${abi_define}")
endforeach()
string(REPLACE ";" "\n" abi_defines "${abi_defines}")
config_define(${abi_defines} _LIBCPP_ABI_DEFINES)
endif()
if (LIBCXX_EXTRA_SITE_DEFINES)
set(extra_site_defines)
foreach (extra_site_define ${LIBCXX_EXTRA_SITE_DEFINES})
# Allow defines such as DEFINE=VAL, transformed into "#define DEFINE VAL".
string(REPLACE "=" " " extra_site_define "${extra_site_define}")
list(APPEND extra_site_defines "#define ${extra_site_define}")
endforeach()
string(REPLACE ";" "\n" extra_site_defines "${extra_site_defines}")
config_define(${extra_site_defines} _LIBCPP_EXTRA_SITE_DEFINES)
endif()
# By default libc++ on Windows expects to use a shared library, which requires
# the headers to use DLL import/export semantics. However when building a
# static library only we modify the headers to disable DLL import/export.
if (DEFINED WIN32 AND LIBCXX_ENABLE_STATIC AND NOT LIBCXX_ENABLE_SHARED)
message(STATUS "Generating custom __config for non-DLL Windows build")
config_define(ON _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
endif()
if (WIN32 AND LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
# If linking libcxxabi statically into libcxx, skip the dllimport attributes
# on symbols we refer to from libcxxabi.
add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
endif()
# Setup all common build flags =================================================
function(cxx_add_common_build_flags target)
cxx_add_basic_build_flags(${target})
cxx_add_warning_flags(${target})
cxx_add_windows_flags(${target})
cxx_add_exception_flags(${target})
cxx_add_rtti_flags(${target})
cxx_add_module_flags(${target})
cxx_link_system_libraries(${target})
endfunction()
#===============================================================================
# Setup Source Code And Tests
#===============================================================================
add_subdirectory(include)
add_subdirectory(src)
add_subdirectory(utils)
set(LIBCXX_TEST_DEPS "cxx_experimental")
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY)
list(APPEND LIBCXX_TEST_DEPS cxx_external_threads)
endif()
if (LIBCXX_INCLUDE_BENCHMARKS)
add_subdirectory(benchmarks)
endif()
if (LIBCXX_INCLUDE_TESTS)
add_subdirectory(test)
add_subdirectory(lib/abi)
endif()
if (LIBCXX_INCLUDE_DOCS)
add_subdirectory(docs)
endif()

View File

@ -0,0 +1,186 @@
This file is a partial list of people who have contributed to the LLVM/libc++
project. If you have contributed a patch or made some other contribution to
LLVM/libc++, please submit a patch to this file to add yourself, and it will be
done!
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Saleem Abdulrasool
E: compnerd@compnerd.org
D: Minor patches and Linux fixes.
N: Ulf Adams
D: Invented the Ryu and Ryu Printf algorithms used in floating-point to_chars, and wrote the initial code.
N: Muiez Ahmed
E: muiez@ibm.com
D: z/OS port.
N: Dan Albert
E: danalbert@google.com
D: Android support and test runner improvements.
N: Dimitry Andric
E: dimitry@andric.com
D: Visibility fixes, minor FreeBSD portability patches.
N: Holger Arnold
E: holgerar@gmail.com
D: Minor fix.
N: Jorg Brown
D: Ported floating-point to_chars from MSVC to libc++.
N: David Chisnall
E: theraven at theravensnest dot org
D: FreeBSD and Solaris ports, libcxxrt support, some atomics work.
N: Marshall Clow
E: mclow.lists@gmail.com
E: marshall@idio.com
D: C++14 support, patches and bug fixes.
N: Jonathan B Coe
E: jbcoe@me.com
D: Implementation of propagate_const.
N: Matthew Dempsky
E: matthew@dempsky.org
D: Minor patches and bug fixes.
N: Christopher Di Bella
E: cjdb@google.com
E: cjdb.ns@gmail.com
D: Library concepts.
N: Glen Joseph Fernandes
E: glenjofe@gmail.com
D: Implementation of to_address.
N: Eric Fiselier
E: eric@efcs.ca
D: LFTS support, patches and bug fixes.
N: Bill Fisher
E: william.w.fisher@gmail.com
D: Regex bug fixes.
N: Google Inc.
D: Copyright owner and contributor of the CityHash algorithm
N: Howard Hinnant
E: hhinnant@apple.com
D: Architect and primary author of libc++
N: Sergej Jaskiewicz
E: jaskiewiczs@icloud.com
D: Minor improvements in the testing infrastructure
N: Hyeon-bin Jeong
E: tuhertz@gmail.com
D: Minor patches and bug fixes.
N: Argyrios Kyrtzidis
E: kyrtzidis@apple.com
D: Bug fixes.
N: Stephan T. Lavavej
E: stl@microsoft.com
E: stl@nuwen.net
D: Implemented floating-point to_chars.
N: Microsoft Corporation
D: Contributed floating-point to_chars.
N: Bruce Mitchener, Jr.
E: bruce.mitchener@gmail.com
D: Emscripten-related changes.
N: Michel Morin
E: mimomorin@gmail.com
D: Minor patches to is_convertible.
N: Andrew Morrow
E: andrew.c.morrow@gmail.com
D: Minor patches and Linux fixes.
N: Michael Park
E: mcypark@gmail.com
D: Implementation of <variant>.
N: Arvid Picciani
E: aep at exys dot org
D: Minor patches and musl port.
N: Bjorn Reese
E: breese@users.sourceforge.net
D: Initial regex prototype
N: Nico Rieck
E: nico.rieck@gmail.com
D: Windows fixes
N: Jon Roelofs
E: jroelofS@jroelofs.com
D: Remote testing, Newlib port, baremetal/single-threaded support.
N: Kent Ross
E: k@mad.cash
D: Patches for operator<=> support
N: Jonathan Sauer
D: Minor patches, mostly related to constexpr
N: Craig Silverstein
E: csilvers@google.com
D: Implemented Cityhash as the string hash function on 64-bit machines
N: Richard Smith
D: Minor patches.
N: Joerg Sonnenberger
E: joerg@NetBSD.org
D: NetBSD port.
N: Stephan Tolksdorf
E: st@quanttec.com
D: Minor <atomic> fix
N: Ruben Van Boxem
E: vanboxem dot ruben at gmail dot com
D: Initial Windows patches.
N: Michael van der Westhuizen
E: r1mikey at gmail dot com
N: Larisse Voufo
D: Minor patches.
N: Klaas de Vries
E: klaas at klaasgaaf dot nl
D: Minor bug fix.
N: Mark de Wever
E: koraq at xs4all dot nl
D: Format library support.
D: Finalized the porting of MSVC's to_chars to libc++.
N: Zhang Xiongpang
E: zhangxiongpang@gmail.com
D: Minor patches and bug fixes.
N: Xing Xue
E: xingxue@ca.ibm.com
D: AIX port
N: Jeffrey Yasskin
E: jyasskin@gmail.com
E: jyasskin@google.com
D: Linux fixes.
N: Zhihao Yuan
E: lichray@gmail.com
D: Standard compatibility fixes.

View File

@ -0,0 +1,311 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
The libc++ library is dual licensed under both the University of Illinois
"BSD-Like" license and the MIT license. As a user of this code you may choose
to use it under either license. As a contributor, you agree to allow your code
to be used under both.
Full text of the relevant licenses is included below.
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,5 @@
## libc++
LLVM libc++, specifically for Android, removing exception and RTTI support.
Source code is extracted from both the upstrean and AOSP `llvm-project` repository.

View File

@ -0,0 +1,23 @@
This is meant to be a general place to list things that should be done "someday"
CXX Runtime Library Tasks
=========================
* Look into mirroring libsupc++'s typeinfo vtable layout when libsupc++/libstdc++
is used as the runtime library.
* Investigate and document interoperability between libc++ and libstdc++ on
linux. Do this for every supported c++ runtime library.
Atomic Related Tasks
====================
* future should use <atomic> for synchronization.
Test Suite Tasks
================
* Improve the quality and portability of the locale test data.
* Convert failure tests to use Clang Verify.
Misc Tasks
==========
* Find all sequences of >2 underscores and eradicate them.
* run clang-tidy on libc++
* Document the "conditionally-supported" bits of libc++

View File

@ -0,0 +1,53 @@
@echo on
if NOT EXIST C:\projects\deps (
mkdir C:\projects\deps
)
cd C:\projects\deps
::###########################################################################
:: Setup Compiler
::###########################################################################
if NOT EXIST llvm-installer.exe (
appveyor DownloadFile https://prereleases.llvm.org/win-snapshots/LLVM-9.0.0-r357435-win32.exe -FileName llvm-installer.exe
)
if "%CLANG_VERSION%"=="ToT" (
START /WAIT llvm-installer.exe /S /D=C:\"Program Files\LLVM"
)
if DEFINED CLANG_VERSION @set PATH="C:\Program Files\LLVM\bin";%PATH%
if DEFINED CLANG_VERSION clang-cl -v
if DEFINED MINGW_PATH rename "C:\Program Files\Git\usr\bin\sh.exe" "sh-ignored.exe"
if DEFINED MINGW_PATH @set "PATH=%PATH:C:\Program Files (x86)\Git\bin=%"
if DEFINED MINGW_PATH @set "PATH=%PATH%;%MINGW_PATH%"
if DEFINED MINGW_PATH g++ -v
::###########################################################################
:: Install a recent CMake
::###########################################################################
if NOT EXIST cmake (
appveyor DownloadFile https://cmake.org/files/v3.7/cmake-3.7.2-win64-x64.zip -FileName cmake.zip
7z x cmake.zip -oC:\projects\deps > nul
move C:\projects\deps\cmake-* C:\projects\deps\cmake
rm cmake.zip
)
@set PATH=C:\projects\deps\cmake\bin;%PATH%
cmake --version
::###########################################################################
:: Install Ninja
::###########################################################################
if NOT EXIST ninja (
appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip
7z x ninja.zip -oC:\projects\deps\ninja > nul
rm ninja.zip
)
@set PATH=C:\projects\deps\ninja;%PATH%
ninja --version
::###########################################################################
:: Setup the cached copy of LLVM
::###########################################################################
git clone --depth=1 http://llvm.org/git/llvm.git
@echo off

View File

@ -0,0 +1,71 @@
version: '{build}'
shallow_clone: true
build:
verbosity: detailed
configuration:
- Debug
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
CMAKE_OPTIONS: -DCMAKE_C_COMPILER=clang-cl.exe -DCMAKE_CXX_COMPILER=clang-cl.exe
CLANG_VERSION: ToT
MSVC_SETUP_PATH: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat
MSVC_SETUP_ARG: x86
GENERATOR: Ninja
MAKE_PROGRAM: ninja
APPVEYOR_SAVE_CACHE_ON_ERROR: true
# TODO: Maybe re-enable this configuration? Do we want to support MSVC 2015's runtime?
# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# MINGW_PATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin
# GENERATOR: MinGW Makefiles
# MAKE_PROGRAM: mingw32-make
# APPVEYOR_SAVE_CACHE_ON_ERROR: true
install:
############################################################################
# All external dependencies are installed in C:\projects\deps
############################################################################
- call "%APPVEYOR_BUILD_FOLDER%\\appveyor-reqs-install.cmd"
before_build:
- if DEFINED MSVC_SETUP_PATH call "%MSVC_SETUP_PATH%" %MSVC_SETUP_ARG%
- cd %APPVEYOR_BUILD_FOLDER%
build_script:
- md C:\projects\build-libcxx
- cd C:\projects\build-libcxx
- echo %configuration%
#############################################################################
# Configuration Step
#############################################################################
- cmake -G "%GENERATOR%" %CMAKE_OPTIONS%
"-DCMAKE_BUILD_TYPE=%configuration%"
"-DLLVM_PATH=C:\projects\deps\llvm"
-DLLVM_LIT_ARGS="-sv --show-xfail --show-unsupported"
%APPVEYOR_BUILD_FOLDER%
#############################################################################
# Build Step
#############################################################################
- "%MAKE_PROGRAM%"
test_script:
- "%MAKE_PROGRAM% check-cxx"
on_failure:
- appveyor PushArtifact CMakeFiles/CMakeOutput.log
- appveyor PushArtifact CMakeFiles/CMakeError.log
artifacts:
- path: '_build/CMakeFiles/*.log'
name: logs
cache:
- C:\projects\deps\ninja
- C:\projects\deps\cmake
- C:\projects\deps\llvm-installer.exe

View File

@ -0,0 +1,233 @@
if (CMAKE_VERSION VERSION_LESS 3.17)
message(WARNING "The libc++ benchmarks won't be available because the version of CMake is too old to support them.")
return()
endif()
include(ExternalProject)
include(CheckCXXCompilerFlag)
#==============================================================================
# Build Google Benchmark for libc++
#==============================================================================
set(CMAKE_FOLDER "${CMAKE_FOLDER}/Benchmarks")
set(BENCHMARK_LIBCXX_COMPILE_FLAGS
-Wno-unused-command-line-argument
-nostdinc++
-isystem "${LIBCXX_GENERATED_INCLUDE_DIR}"
-L${LIBCXX_LIBRARY_DIR}
-Wl,-rpath,${LIBCXX_LIBRARY_DIR}
${SANITIZER_FLAGS}
)
if(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR AND NOT APPLE)
list(APPEND BENCHMARK_LIBCXX_COMPILE_FLAGS
-isystem "${LIBCXX_GENERATED_INCLUDE_TARGET_DIR}")
endif()
if (DEFINED LIBCXX_CXX_ABI_LIBRARY_PATH)
list(APPEND BENCHMARK_LIBCXX_COMPILE_FLAGS
-L${LIBCXX_CXX_ABI_LIBRARY_PATH}
-Wl,-rpath,${LIBCXX_CXX_ABI_LIBRARY_PATH})
endif()
split_list(BENCHMARK_LIBCXX_COMPILE_FLAGS)
ExternalProject_Add(google-benchmark-libcxx
EXCLUDE_FROM_ALL ON
DEPENDS cxx cxx-headers
PREFIX benchmark-libcxx
SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/benchmark-libcxx
CMAKE_CACHE_ARGS
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-DCMAKE_BUILD_TYPE:STRING=RELEASE
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_CXX_FLAGS:STRING=${BENCHMARK_LIBCXX_COMPILE_FLAGS}
-DBENCHMARK_USE_LIBCXX:BOOL=ON
-DBENCHMARK_ENABLE_TESTING:BOOL=OFF)
#==============================================================================
# Build Google Benchmark for the native stdlib
#==============================================================================
set(BENCHMARK_NATIVE_TARGET_FLAGS)
if (LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN)
set(BENCHMARK_NATIVE_TARGET_FLAGS
--gcc-toolchain=${LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN})
endif()
split_list(BENCHMARK_NATIVE_TARGET_FLAGS)
if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
ExternalProject_Add(google-benchmark-native
EXCLUDE_FROM_ALL ON
PREFIX benchmark-native
SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/benchmark-native
CMAKE_CACHE_ARGS
-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_FLAGS:STRING=${BENCHMARK_NATIVE_TARGET_FLAGS}
-DCMAKE_BUILD_TYPE:STRING=RELEASE
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DBENCHMARK_ENABLE_TESTING:BOOL=OFF)
endif()
#==============================================================================
# Benchmark tests configuration
#==============================================================================
add_custom_target(cxx-benchmarks)
set(BENCHMARK_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(BENCHMARK_LIBCXX_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/benchmark-libcxx)
set(BENCHMARK_NATIVE_INSTALL ${CMAKE_CURRENT_BINARY_DIR}/benchmark-native)
add_library( cxx-benchmarks-flags INTERFACE)
target_compile_features( cxx-benchmarks-flags INTERFACE cxx_std_20)
target_compile_options( cxx-benchmarks-flags INTERFACE -fsized-deallocation -nostdinc++)
target_include_directories(cxx-benchmarks-flags INTERFACE "${LIBCXX_GENERATED_INCLUDE_DIR}"
INTERFACE "${BENCHMARK_LIBCXX_INSTALL}/include"
INTERFACE "${LIBCXX_SOURCE_DIR}/test/support")
add_library( cxx-benchmarks-flags-native INTERFACE)
target_link_libraries( cxx-benchmarks-flags-native INTERFACE cxx-benchmarks-flags)
target_compile_options(cxx-benchmarks-flags-native INTERFACE ${BENCHMARK_NATIVE_TARGET_FLAGS})
target_link_options( cxx-benchmarks-flags-native INTERFACE ${BENCHMARK_NATIVE_TARGET_FLAGS} "-L${BENCHMARK_NATIVE_INSTALL}/lib")
if (LIBCXX_BENCHMARK_NATIVE_STDLIB STREQUAL "libstdc++")
find_library(LIBSTDCXX_FILESYSTEM_TEST stdc++fs
PATHS ${LIBCXX_BENCHMARK_NATIVE_GCC_TOOLCHAIN}
PATH_SUFFIXES lib lib64
DOC "The libstdc++ filesystem library used by the benchmarks"
)
if (LIBSTDCXX_FILESYSTEM_TEST)
target_link_libraries(cxx-benchmarks-flags-native INTERFACE -lstdc++fs)
endif()
else()
target_link_libraries(cxx-benchmarks-flags-native INTERFACE -lc++fs -lc++experimental)
endif()
add_library( cxx-benchmarks-flags-libcxx INTERFACE)
target_link_libraries( cxx-benchmarks-flags-libcxx INTERFACE cxx-benchmarks-flags)
target_compile_options(cxx-benchmarks-flags-libcxx INTERFACE ${SANITIZER_FLAGS} -Wno-user-defined-literals -Wno-suggest-override)
target_link_options( cxx-benchmarks-flags-libcxx INTERFACE -nodefaultlibs "-L${BENCHMARK_LIBCXX_INSTALL}/lib" ${SANITIZER_FLAGS})
set(libcxx_benchmark_targets)
function(add_benchmark_test name source_file)
set(libcxx_target ${name}_libcxx)
list(APPEND libcxx_benchmark_targets ${libcxx_target})
add_executable(${libcxx_target} EXCLUDE_FROM_ALL ${source_file})
target_link_libraries(${libcxx_target} PRIVATE cxx-benchmarks-flags-libcxx)
add_dependencies(${libcxx_target} cxx google-benchmark-libcxx)
add_dependencies(cxx-benchmarks ${libcxx_target})
if (LIBCXX_ENABLE_SHARED)
target_link_libraries(${libcxx_target} PRIVATE cxx_shared)
else()
target_link_libraries(${libcxx_target} PRIVATE cxx_static)
endif()
target_link_libraries(${libcxx_target} PRIVATE cxx_experimental benchmark)
if (LLVM_USE_SANITIZER)
target_link_libraries(${libcxx_target} PRIVATE -ldl)
endif()
set_target_properties(${libcxx_target}
PROPERTIES
OUTPUT_NAME "${name}.libcxx.out"
RUNTIME_OUTPUT_DIRECTORY "${BENCHMARK_OUTPUT_DIR}"
CXX_EXTENSIONS NO)
cxx_link_system_libraries(${libcxx_target})
if (LIBCXX_BENCHMARK_NATIVE_STDLIB)
set(native_target ${name}_native)
add_executable(${native_target} EXCLUDE_FROM_ALL ${source_file})
target_link_libraries(${native_target} PRIVATE cxx-benchmarks-flags-native)
add_dependencies(${native_target} google-benchmark-native
google-benchmark-libcxx)
target_link_libraries(${native_target} PRIVATE -lbenchmark)
if (LIBCXX_HAS_PTHREAD_LIB)
target_link_libraries(${native_target} PRIVATE -pthread)
endif()
add_dependencies(cxx-benchmarks ${native_target})
set_target_properties(${native_target}
PROPERTIES
OUTPUT_NAME "${name}.native.out"
RUNTIME_OUTPUT_DIRECTORY "${BENCHMARK_OUTPUT_DIR}"
CXX_EXTENSIONS NO)
endif()
endfunction()
#==============================================================================
# Register Benchmark tests
#==============================================================================
set(BENCHMARK_TESTS
algorithms.partition_point.bench.cpp
algorithms/lower_bound.bench.cpp
algorithms/make_heap.bench.cpp
algorithms/make_heap_then_sort_heap.bench.cpp
algorithms/min_max_element.bench.cpp
algorithms/pop_heap.bench.cpp
algorithms/push_heap.bench.cpp
algorithms/ranges_make_heap.bench.cpp
algorithms/ranges_make_heap_then_sort_heap.bench.cpp
algorithms/ranges_pop_heap.bench.cpp
algorithms/ranges_push_heap.bench.cpp
algorithms/ranges_sort.bench.cpp
algorithms/ranges_sort_heap.bench.cpp
algorithms/ranges_stable_sort.bench.cpp
algorithms/sort.bench.cpp
algorithms/sort_heap.bench.cpp
algorithms/stable_sort.bench.cpp
allocation.bench.cpp
deque.bench.cpp
deque_iterator.bench.cpp
filesystem.bench.cpp
format_to_n.bench.cpp
format_to.bench.cpp
format.bench.cpp
formatted_size.bench.cpp
formatter_float.bench.cpp
formatter_int.bench.cpp
function.bench.cpp
join_view.bench.cpp
map.bench.cpp
monotonic_buffer.bench.cpp
ordered_set.bench.cpp
std_format_spec_string_unicode.bench.cpp
string.bench.cpp
stringstream.bench.cpp
to_chars.bench.cpp
unordered_set_operations.bench.cpp
util_smartptr.bench.cpp
variant_visit_1.bench.cpp
variant_visit_2.bench.cpp
variant_visit_3.bench.cpp
vector_operations.bench.cpp
)
foreach(test_path ${BENCHMARK_TESTS})
get_filename_component(test_file "${test_path}" NAME)
string(REPLACE ".bench.cpp" "" test_name "${test_file}")
if (NOT DEFINED ${test_name}_REPORTED)
message(STATUS "Adding Benchmark: ${test_file}")
# Only report the adding of the benchmark once.
set(${test_name}_REPORTED ON CACHE INTERNAL "")
endif()
add_benchmark_test(${test_name} ${test_path})
endforeach()
if (LIBCXX_INCLUDE_TESTS)
include(AddLLVM)
if (NOT DEFINED LIBCXX_TEST_DEPS)
message(FATAL_ERROR "Expected LIBCXX_TEST_DEPS to be defined")
endif()
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
set(BENCHMARK_LIT_ARGS "--show-all --show-xfail --show-unsupported ${LIT_ARGS_DEFAULT}")
add_lit_target(check-cxx-benchmarks
"Running libcxx benchmarks tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS cxx-benchmarks ${LIBCXX_TEST_DEPS}
ARGS ${BENCHMARK_LIT_ARGS})
endif()

View File

@ -0,0 +1,133 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <string>
#include <tuple>
#include <type_traits>
#include <vector>
#include "benchmark/benchmark.h"
#include "test_macros.h"
namespace internal {
template <class D, class E, size_t I>
struct EnumValue : std::integral_constant<E, static_cast<E>(I)> {
static std::string name() { return std::string("_") + D::Names[I]; }
};
template <class D, class E, size_t ...Idxs>
constexpr auto makeEnumValueTuple(std::index_sequence<Idxs...>) {
return std::make_tuple(EnumValue<D, E, Idxs>{}...);
}
template <class B>
static auto skip(const B& Bench, int) -> decltype(Bench.skip()) {
return Bench.skip();
}
template <class B>
static auto skip(const B& Bench, char) {
return false;
}
template <class B, class Args, size_t... Is>
void makeBenchmarkFromValuesImpl(const Args& A, std::index_sequence<Is...>) {
for (auto& V : A) {
B Bench{std::get<Is>(V)...};
if (!internal::skip(Bench, 0)) {
benchmark::RegisterBenchmark(Bench.name().c_str(),
[=](benchmark::State& S) { Bench.run(S); });
}
}
}
template <class B, class... Args>
void makeBenchmarkFromValues(const std::vector<std::tuple<Args...> >& A) {
makeBenchmarkFromValuesImpl<B>(A, std::index_sequence_for<Args...>());
}
template <template <class...> class B, class Args, class... U>
void makeBenchmarkImpl(const Args& A, std::tuple<U...> t) {
makeBenchmarkFromValues<B<U...> >(A);
}
template <template <class...> class B, class Args, class... U,
class... T, class... Tuples>
void makeBenchmarkImpl(const Args& A, std::tuple<U...>, std::tuple<T...>,
Tuples... rest) {
(internal::makeBenchmarkImpl<B>(A, std::tuple<U..., T>(), rest...), ...);
}
template <class R, class T>
void allValueCombinations(R& Result, const T& Final) {
return Result.push_back(Final);
}
template <class R, class T, class V, class... Vs>
void allValueCombinations(R& Result, const T& Prev, const V& Value,
const Vs&... Values) {
for (const auto& E : Value) {
allValueCombinations(Result, std::tuple_cat(Prev, std::make_tuple(E)),
Values...);
}
}
} // namespace internal
// CRTP class that enables using enum types as a dimension for
// makeCartesianProductBenchmark below.
// The type passed to `B` will be a std::integral_constant<E, e>, with the
// additional static function `name()` that returns the stringified name of the
// label.
//
// Eg:
// enum class MyEnum { A, B };
// struct AllMyEnum : EnumValuesAsTuple<AllMyEnum, MyEnum, 2> {
// static constexpr absl::string_view Names[] = {"A", "B"};
// };
template <class Derived, class EnumType, size_t NumLabels>
using EnumValuesAsTuple =
decltype(internal::makeEnumValueTuple<Derived, EnumType>(
std::make_index_sequence<NumLabels>{}));
// Instantiates B<T0, T1, ..., TN> where <Ti...> are the combinations in the
// cartesian product of `Tuples...`, and pass (arg0, ..., argN) as constructor
// arguments where `(argi...)` are the combination in the cartesian product of
// the runtime values of `A...`.
// B<T...> requires:
// - std::string name(args...): The name of the benchmark.
// - void run(benchmark::State&, args...): The body of the benchmark.
// It can also optionally provide:
// - bool skip(args...): When `true`, skips the combination. Default is false.
//
// Returns int to facilitate registration. The return value is unspecified.
template <template <class...> class B, class... Tuples, class... Args>
int makeCartesianProductBenchmark(const Args&... A) {
std::vector<std::tuple<typename Args::value_type...> > V;
internal::allValueCombinations(V, std::tuple<>(), A...);
internal::makeBenchmarkImpl<B>(V, std::tuple<>(), Tuples()...);
return 0;
}
template <class B, class... Args>
int makeCartesianProductBenchmark(const Args&... A) {
std::vector<std::tuple<typename Args::value_type...> > V;
internal::allValueCombinations(V, std::tuple<>(), A...);
internal::makeBenchmarkFromValues<B>(V);
return 0;
}
// When `opaque` is true, this function hides the runtime state of `value` from
// the optimizer.
// It returns `value`.
template <class T>
TEST_ALWAYS_INLINE inline T maybeOpaque(T value, bool opaque) {
if (opaque) benchmark::DoNotOptimize(value);
return value;
}

View File

@ -0,0 +1,154 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef BENCHMARK_CONTAINER_BENCHMARKS_H
#define BENCHMARK_CONTAINER_BENCHMARKS_H
#include <cassert>
#include "Utilities.h"
#include "benchmark/benchmark.h"
namespace ContainerBenchmarks {
template <class Container>
void BM_ConstructSize(benchmark::State& st, Container) {
auto size = st.range(0);
for (auto _ : st) {
Container c(size);
DoNotOptimizeData(c);
}
}
template <class Container>
void BM_ConstructSizeValue(benchmark::State& st, Container, typename Container::value_type const& val) {
const auto size = st.range(0);
for (auto _ : st) {
Container c(size, val);
DoNotOptimizeData(c);
}
}
template <class Container, class GenInputs>
void BM_ConstructIterIter(benchmark::State& st, Container, GenInputs gen) {
auto in = gen(st.range(0));
const auto begin = in.begin();
const auto end = in.end();
benchmark::DoNotOptimize(&in);
while (st.KeepRunning()) {
Container c(begin, end);
DoNotOptimizeData(c);
}
}
template <class Container, class GenInputs>
void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) {
auto in = gen(st.range(0));
const auto end = in.end();
while (st.KeepRunning()) {
c.clear();
for (auto it = in.begin(); it != end; ++it) {
benchmark::DoNotOptimize(&(*c.insert(*it).first));
}
benchmark::ClobberMemory();
}
}
template <class Container, class GenInputs>
void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) {
auto in = gen(st.range(0));
const auto end = in.end();
while (st.KeepRunning()) {
c.clear();
c.rehash(16);
for (auto it = in.begin(); it != end; ++it) {
benchmark::DoNotOptimize(&(*c.insert(*it).first));
}
benchmark::ClobberMemory();
}
}
template <class Container, class GenInputs>
void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) {
auto in = gen(st.range(0));
const auto end = in.end();
c.insert(in.begin(), in.end());
benchmark::DoNotOptimize(&c);
benchmark::DoNotOptimize(&in);
while (st.KeepRunning()) {
for (auto it = in.begin(); it != end; ++it) {
benchmark::DoNotOptimize(&(*c.insert(*it).first));
}
benchmark::ClobberMemory();
}
}
template <class Container, class GenInputs>
void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) {
auto in = gen(st.range(0));
const auto end = in.end();
c.insert(in.begin(), in.end());
benchmark::DoNotOptimize(&c);
benchmark::DoNotOptimize(&in);
while (st.KeepRunning()) {
for (auto it = in.begin(); it != end; ++it) {
benchmark::DoNotOptimize(&(*c.emplace(*it).first));
}
benchmark::ClobberMemory();
}
}
template <class Container, class GenInputs>
static void BM_Find(benchmark::State& st, Container c, GenInputs gen) {
auto in = gen(st.range(0));
c.insert(in.begin(), in.end());
benchmark::DoNotOptimize(&(*c.begin()));
const auto end = in.data() + in.size();
while (st.KeepRunning()) {
for (auto it = in.data(); it != end; ++it) {
benchmark::DoNotOptimize(&(*c.find(*it)));
}
benchmark::ClobberMemory();
}
}
template <class Container, class GenInputs>
static void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) {
c.rehash(8);
auto in = gen(st.range(0));
c.insert(in.begin(), in.end());
benchmark::DoNotOptimize(&(*c.begin()));
const auto end = in.data() + in.size();
while (st.KeepRunning()) {
for (auto it = in.data(); it != end; ++it) {
benchmark::DoNotOptimize(&(*c.find(*it)));
}
benchmark::ClobberMemory();
}
}
template <class Container, class GenInputs>
static void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) {
auto in = gen(st.range(0));
c.max_load_factor(3.0);
c.insert(in.begin(), in.end());
benchmark::DoNotOptimize(c);
const auto bucket_count = c.bucket_count();
while (st.KeepRunning()) {
c.rehash(bucket_count + 1);
c.rehash(bucket_count);
benchmark::ClobberMemory();
}
}
} // end namespace ContainerBenchmarks
#endif // BENCHMARK_CONTAINER_BENCHMARKS_H

View File

@ -0,0 +1,143 @@
#ifndef BENCHMARK_GENERATE_INPUT_H
#define BENCHMARK_GENERATE_INPUT_H
#include <algorithm>
#include <random>
#include <vector>
#include <string>
#include <climits>
#include <cstddef>
static const char Letters[] = {
'0','1','2','3','4',
'5','6','7','8','9',
'A','B','C','D','E','F',
'G','H','I','J','K',
'L','M','N','O','P',
'Q','R','S','T','U',
'V','W','X','Y','Z',
'a','b','c','d','e','f',
'g','h','i','j','k',
'l','m','n','o','p',
'q','r','s','t','u',
'v','w','x','y','z'
};
static const std::size_t LettersSize = sizeof(Letters);
inline std::default_random_engine& getRandomEngine() {
static std::default_random_engine RandEngine(std::random_device{}());
return RandEngine;
}
inline char getRandomChar() {
std::uniform_int_distribution<> LettersDist(0, LettersSize-1);
return Letters[LettersDist(getRandomEngine())];
}
template <class IntT>
inline IntT getRandomInteger(IntT Min, IntT Max) {
std::uniform_int_distribution<unsigned long long> dist(Min, Max);
return static_cast<IntT>(dist(getRandomEngine()));
}
inline std::string getRandomString(std::size_t Len) {
std::string str(Len, 0);
std::generate_n(str.begin(), Len, &getRandomChar);
return str;
}
template <class IntT>
inline std::vector<IntT> getDuplicateIntegerInputs(size_t N) {
std::vector<IntT> inputs(N, static_cast<IntT>(-1));
return inputs;
}
template <class IntT>
inline std::vector<IntT> getSortedIntegerInputs(size_t N) {
std::vector<IntT> inputs;
for (size_t i=0; i < N; i += 1)
inputs.push_back(i);
return inputs;
}
template <class IntT>
std::vector<IntT> getSortedLargeIntegerInputs(size_t N) {
std::vector<IntT> inputs;
for (size_t i=0; i < N; ++i) {
inputs.push_back(i + N);
}
return inputs;
}
template <class IntT>
std::vector<IntT> getSortedTopBitsIntegerInputs(size_t N) {
std::vector<IntT> inputs = getSortedIntegerInputs<IntT>(N);
for (auto& E : inputs) E <<= ((sizeof(IntT) / 2) * CHAR_BIT);
return inputs;
}
template <class IntT>
inline std::vector<IntT> getReverseSortedIntegerInputs(size_t N) {
std::vector<IntT> inputs;
std::size_t i = N;
while (i > 0) {
--i;
inputs.push_back(i);
}
return inputs;
}
template <class IntT>
std::vector<IntT> getPipeOrganIntegerInputs(size_t N) {
std::vector<IntT> v; v.reserve(N);
for (size_t i = 0; i < N/2; ++i) v.push_back(i);
for (size_t i = N/2; i < N; ++i) v.push_back(N - i);
return v;
}
template <class IntT>
std::vector<IntT> getRandomIntegerInputs(size_t N) {
std::vector<IntT> inputs;
for (size_t i=0; i < N; ++i) {
inputs.push_back(getRandomInteger<IntT>(0, std::numeric_limits<IntT>::max()));
}
return inputs;
}
inline std::vector<std::string> getDuplicateStringInputs(size_t N) {
std::vector<std::string> inputs(N, getRandomString(1024));
return inputs;
}
inline std::vector<std::string> getRandomStringInputs(size_t N) {
std::vector<std::string> inputs;
for (size_t i=0; i < N; ++i) {
inputs.push_back(getRandomString(1024));
}
return inputs;
}
inline std::vector<std::string> getSortedStringInputs(size_t N) {
std::vector<std::string> inputs = getRandomStringInputs(N);
std::sort(inputs.begin(), inputs.end());
return inputs;
}
inline std::vector<std::string> getReverseSortedStringInputs(size_t N) {
std::vector<std::string> inputs = getSortedStringInputs(N);
std::reverse(inputs.begin(), inputs.end());
return inputs;
}
inline std::vector<const char*> getRandomCStringInputs(size_t N) {
static std::vector<std::string> inputs = getRandomStringInputs(N);
std::vector<const char*> cinputs;
for (auto const& str : inputs)
cinputs.push_back(str.c_str());
return cinputs;
}
#endif // BENCHMARK_GENERATE_INPUT_H

View File

@ -0,0 +1,33 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef BENCHMARK_UTILITIES_H
#define BENCHMARK_UTILITIES_H
#include <cassert>
#include <type_traits>
#include "benchmark/benchmark.h"
namespace UtilitiesInternal {
template <class Container>
auto HaveDataImpl(int) -> decltype((std::declval<Container&>().data(), std::true_type{}));
template <class Container>
auto HaveDataImpl(long) -> std::false_type;
template <class T>
using HasData = decltype(HaveDataImpl<T>(0));
} // namespace UtilitiesInternal
template <class Container, std::enable_if_t<UtilitiesInternal::HasData<Container>::value>* = nullptr>
void DoNotOptimizeData(Container &c) { benchmark::DoNotOptimize(c.data()); }
template <class Container, std::enable_if_t<!UtilitiesInternal::HasData<Container>::value>* = nullptr>
void DoNotOptimizeData(Container &c) { benchmark::DoNotOptimize(&c); }
#endif // BENCHMARK_UTILITIES_H

View File

@ -0,0 +1,58 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef BENCHMARK_VARIANT_BENCHMARKS_H
#define BENCHMARK_VARIANT_BENCHMARKS_H
#include <array>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <variant>
#include "benchmark/benchmark.h"
#include "GenerateInput.h"
namespace VariantBenchmarks {
template <std::size_t I>
struct S {
static constexpr size_t v = I;
};
template <std::size_t N, std::size_t... Is>
static auto genVariants(std::index_sequence<Is...>) {
using V = std::variant<S<Is>...>;
using F = V (*)();
static constexpr F fs[] = {[] { return V(std::in_place_index<Is>); }...};
std::array<V, N> result = {};
for (auto& v : result) {
v = fs[getRandomInteger(0ul, sizeof...(Is) - 1)]();
}
return result;
}
template <std::size_t N, std::size_t Alts>
static void BM_Visit(benchmark::State& state) {
auto args = genVariants<N>(std::make_index_sequence<Alts>{});
for (auto _ : state) {
benchmark::DoNotOptimize(std::apply(
[](auto... vs) {
return std::visit([](auto... is) { return (is.v + ... + 0); }, vs...);
},
args));
}
}
} // end namespace VariantBenchmarks
#endif // BENCHMARK_VARIANT_BENCHMARKS_H

View File

@ -0,0 +1,124 @@
#include <array>
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <tuple>
#include <vector>
#include "benchmark/benchmark.h"
#include "CartesianBenchmarks.h"
#include "GenerateInput.h"
namespace {
template <typename I, typename N>
std::array<I, 10> every_10th_percentile_N(I first, N n) {
N step = n / 10;
std::array<I, 10> res;
for (size_t i = 0; i < 10; ++i) {
res[i] = first;
std::advance(first, step);
}
return res;
}
template <class IntT>
struct TestIntBase {
static std::vector<IntT> generateInput(size_t size) {
std::vector<IntT> Res(size);
std::generate(Res.begin(), Res.end(),
[] { return getRandomInteger<IntT>(0, std::numeric_limits<IntT>::max()); });
return Res;
}
};
struct TestInt32 : TestIntBase<std::int32_t> {
static constexpr const char* Name = "TestInt32";
};
struct TestInt64 : TestIntBase<std::int64_t> {
static constexpr const char* Name = "TestInt64";
};
struct TestUint32 : TestIntBase<std::uint32_t> {
static constexpr const char* Name = "TestUint32";
};
struct TestMediumString {
static constexpr const char* Name = "TestMediumString";
static constexpr size_t StringSize = 32;
static std::vector<std::string> generateInput(size_t size) {
std::vector<std::string> Res(size);
std::generate(Res.begin(), Res.end(), [] { return getRandomString(StringSize); });
return Res;
}
};
using AllTestTypes = std::tuple<TestInt32, TestInt64, TestUint32, TestMediumString>;
struct LowerBoundAlg {
template <class I, class V>
I operator()(I first, I last, const V& value) const {
return std::lower_bound(first, last, value);
}
static constexpr const char* Name = "LowerBoundAlg";
};
struct UpperBoundAlg {
template <class I, class V>
I operator()(I first, I last, const V& value) const {
return std::upper_bound(first, last, value);
}
static constexpr const char* Name = "UpperBoundAlg";
};
struct EqualRangeAlg {
template <class I, class V>
std::pair<I, I> operator()(I first, I last, const V& value) const {
return std::equal_range(first, last, value);
}
static constexpr const char* Name = "EqualRangeAlg";
};
using AllAlgs = std::tuple<LowerBoundAlg, UpperBoundAlg, EqualRangeAlg>;
template <class Alg, class TestType>
struct PartitionPointBench {
size_t Quantity;
std::string name() const {
return std::string("PartitionPointBench_") + Alg::Name + "_" +
TestType::Name + '/' + std::to_string(Quantity);
}
void run(benchmark::State& state) const {
auto Data = TestType::generateInput(Quantity);
std::sort(Data.begin(), Data.end());
auto Every10Percentile = every_10th_percentile_N(Data.begin(), Data.size());
for (auto _ : state) {
for (auto Test : Every10Percentile)
benchmark::DoNotOptimize(Alg{}(Data.begin(), Data.end(), *Test));
}
}
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
const std::vector<size_t> Quantities = {1 << 8, 1 << 10, 1 << 20};
makeCartesianProductBenchmark<PartitionPointBench, AllAlgs, AllTestTypes>(
Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,244 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LIBCXX_ALGORITHMS_COMMON_H
#define LIBCXX_ALGORITHMS_COMMON_H
#include <algorithm>
#include <numeric>
#include <tuple>
#include <vector>
#include "../CartesianBenchmarks.h"
#include "../GenerateInput.h"
enum class ValueType { Uint32, Uint64, Pair, Tuple, String, Float };
struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 6> {
static constexpr const char* Names[] = {"uint32", "uint64", "pair<uint32, uint32>", "tuple<uint32, uint64, uint32>",
"string", "float"};
};
using Types = std::tuple< uint32_t, uint64_t, std::pair<uint32_t, uint32_t>, std::tuple<uint32_t, uint64_t, uint32_t>,
std::string, float >;
template <class V>
using Value = std::tuple_element_t<(int)V::value, Types>;
enum class Order {
Random,
Ascending,
Descending,
SingleElement,
PipeOrgan,
Heap,
QuickSortAdversary,
};
struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 7> {
static constexpr const char* Names[] = {"Random", "Ascending",
"Descending", "SingleElement",
"PipeOrgan", "Heap",
"QuickSortAdversary"};
};
// fillAdversarialQuickSortInput fills the input vector with N int-like values.
// These values are arranged in such a way that they would invoke O(N^2)
// behavior on any quick sort implementation that satisifies certain conditions.
// Details are available in the following paper:
// "A Killer Adversary for Quicksort", M. D. McIlroy, Software-Practice &
// Experience Volume 29 Issue 4 April 10, 1999 pp 341-344.
// https://dl.acm.org/doi/10.5555/311868.311871.
template <class T>
void fillAdversarialQuickSortInput(T& V, size_t N) {
assert(N > 0);
// If an element is equal to gas, it indicates that the value of the element
// is still to be decided and may change over the course of time.
const unsigned int gas = N - 1;
V.resize(N);
for (unsigned int i = 0; i < N; ++i) {
V[i] = gas;
}
// Candidate for the pivot position.
int candidate = 0;
int nsolid = 0;
// Populate all positions in the generated input to gas.
std::vector<int> ascVals(V.size());
// Fill up with ascending values from 0 to V.size()-1. These will act as
// indices into V.
std::iota(ascVals.begin(), ascVals.end(), 0);
std::sort(ascVals.begin(), ascVals.end(), [&](int x, int y) {
if (V[x] == gas && V[y] == gas) {
// We are comparing two inputs whose value is still to be decided.
if (x == candidate) {
V[x] = nsolid++;
} else {
V[y] = nsolid++;
}
}
if (V[x] == gas) {
candidate = x;
} else if (V[y] == gas) {
candidate = y;
}
return V[x] < V[y];
});
}
template <typename T>
void fillValues(std::vector<T>& V, size_t N, Order O) {
if (O == Order::SingleElement) {
V.resize(N, 0);
} else if (O == Order::QuickSortAdversary) {
fillAdversarialQuickSortInput(V, N);
} else {
while (V.size() < N)
V.push_back(V.size());
}
}
template <typename T>
void fillValues(std::vector<std::pair<T, T> >& V, size_t N, Order O) {
if (O == Order::SingleElement) {
V.resize(N, std::make_pair(0, 0));
} else {
while (V.size() < N)
// Half of array will have the same first element.
if (V.size() % 2) {
V.push_back(std::make_pair(V.size(), V.size()));
} else {
V.push_back(std::make_pair(0, V.size()));
}
}
}
template <typename T1, typename T2, typename T3>
void fillValues(std::vector<std::tuple<T1, T2, T3> >& V, size_t N, Order O) {
if (O == Order::SingleElement) {
V.resize(N, std::make_tuple(0, 0, 0));
} else {
while (V.size() < N)
// One third of array will have the same first element.
// One third of array will have the same first element and the same second element.
switch (V.size() % 3) {
case 0:
V.push_back(std::make_tuple(V.size(), V.size(), V.size()));
break;
case 1:
V.push_back(std::make_tuple(0, V.size(), V.size()));
break;
case 2:
V.push_back(std::make_tuple(0, 0, V.size()));
break;
}
}
}
inline void fillValues(std::vector<std::string>& V, size_t N, Order O) {
if (O == Order::SingleElement) {
V.resize(N, getRandomString(64));
} else {
while (V.size() < N)
V.push_back(getRandomString(64));
}
}
template <class T>
void sortValues(T& V, Order O) {
switch (O) {
case Order::Random: {
std::random_device R;
std::mt19937 M(R());
std::shuffle(V.begin(), V.end(), M);
break;
}
case Order::Ascending:
std::sort(V.begin(), V.end());
break;
case Order::Descending:
std::sort(V.begin(), V.end(), std::greater<>());
break;
case Order::SingleElement:
// Nothing to do
break;
case Order::PipeOrgan:
std::sort(V.begin(), V.end());
std::reverse(V.begin() + V.size() / 2, V.end());
break;
case Order::Heap:
std::make_heap(V.begin(), V.end());
break;
case Order::QuickSortAdversary:
// Nothing to do
break;
}
}
constexpr size_t TestSetElements =
#if !TEST_HAS_FEATURE(memory_sanitizer)
1 << 18;
#else
1 << 14;
#endif
template <class ValueType>
std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
Order O) {
std::vector<std::vector<Value<ValueType> > > Ret;
const size_t NumCopies = std::max(size_t{1}, TestSetElements / N);
Ret.resize(NumCopies);
for (auto& V : Ret) {
fillValues(V, N, O);
sortValues(V, O);
}
return Ret;
}
template <class T, class U>
TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
U& Orig) {
state.PauseTiming();
for (auto& Copy : Copies)
Copy = Orig;
state.ResumeTiming();
}
enum class BatchSize {
CountElements,
CountBatch,
};
template <class ValueType, class F>
void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
BatchSize Count, F Body) {
auto Copies = makeOrderedValues<ValueType>(Quantity, O);
auto Orig = Copies;
const size_t Batch = Count == BatchSize::CountElements
? Copies.size() * Quantity
: Copies.size();
while (state.KeepRunningBatch(Batch)) {
for (auto& Copy : Copies) {
Body(Copy);
benchmark::DoNotOptimize(Copy);
}
state.PauseTiming();
Copies = Orig;
state.ResumeTiming();
}
}
const std::vector<size_t> Quantities = {1 << 0, 1 << 2, 1 << 4, 1 << 6,
1 << 8, 1 << 10, 1 << 14,
// Running each benchmark in parallel consumes too much memory with MSAN
// and can lead to the test process being killed.
#if !TEST_HAS_FEATURE(memory_sanitizer)
1 << 18
#endif
};
#endif // LIBCXX_ALGORITHMS_COMMON_H

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <numeric>
#include <random>
#include <vector>
#include "common.h"
namespace {
template <class ValueType>
struct LowerBound {
size_t Quantity;
mutable std::mt19937_64 rng { std::random_device{}() };
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(state, Quantity, Order::Ascending, BatchSize::CountBatch, [&](auto& Copy) {
auto result = std::lower_bound(Copy.begin(), Copy.end(), Copy[rng() % Copy.size()]);
benchmark::DoNotOptimize(result);
});
}
std::string name() const {
return "BM_LowerBound" + ValueType::name() + "_" + std::to_string(Quantity);
}
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<LowerBound, AllValueTypes>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct MakeHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) { std::make_heap(Copy.begin(), Copy.end()); });
}
std::string name() const {
return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<MakeHeap, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct MakeThenSortHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) {
std::make_heap(Copy.begin(), Copy.end());
std::sort_heap(Copy.begin(), Copy.end());
});
}
std::string name() const {
return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<MakeThenSortHeap, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct MinMaxElement {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
benchmark::DoNotOptimize(std::minmax_element(Copy.begin(), Copy.end()));
});
}
std::string name() const {
return "BM_MinMaxElement" + ValueType::name() + Order::name() + "_" + std::to_string(Quantity);
}
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<MinMaxElement, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType>
struct PopHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
std::pop_heap(B, I);
}
});
}
std::string name() const {
return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct PushHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
std::push_heap(Copy.begin(), I + 1);
}
});
}
bool skip() const { return Order() == ::Order::Heap; }
std::string name() const {
return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,37 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct RangesMakeHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) { std::ranges::make_heap(Copy); });
}
std::string name() const {
return "BM_RangesMakeHeap" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<RangesMakeHeap, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct RangesMakeThenSortHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) {
std::ranges::make_heap(Copy);
std::ranges::sort_heap(Copy);
});
}
std::string name() const {
return "BM_RangesMakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<RangesMakeThenSortHeap, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType>
struct RangesPopHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
std::ranges::pop_heap(B, I);
}
});
}
std::string name() const {
return "BM_RangesPopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<RangesPopHeap, AllValueTypes>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct RangesPushHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
std::ranges::push_heap(Copy.begin(), I + 1);
}
});
}
bool skip() const { return Order() == ::Order::Heap; }
std::string name() const {
return "BM_RangesPushHeap" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<RangesPushHeap, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct Sort {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) { std::ranges::sort(Copy); });
}
bool skip() const { return Order() == ::Order::Heap; }
std::string name() const {
return "BM_RangesSort" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
}
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType>
struct RangesSortHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order::Heap, BatchSize::CountElements,
[](auto& Copy) { std::ranges::sort_heap(Copy); });
}
std::string name() const {
return "BM_RangesSortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<RangesSortHeap, AllValueTypes>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct StableSort {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) { std::ranges::stable_sort(Copy); });
}
bool skip() const { return Order() == ::Order::Heap; }
std::string name() const {
return "BM_RangesStableSort" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
}
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct Sort {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) { std::sort(Copy.begin(), Copy.end()); });
}
bool skip() const { return Order() == ::Order::Heap; }
std::string name() const {
return "BM_Sort" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType>
struct SortHeap {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order::Heap, BatchSize::CountElements,
[](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
}
std::string name() const {
return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<SortHeap, AllValueTypes>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include "common.h"
namespace {
template <class ValueType, class Order>
struct StableSort {
size_t Quantity;
void run(benchmark::State& state) const {
runOpOnCopies<ValueType>(
state, Quantity, Order(), BatchSize::CountElements,
[](auto& Copy) { std::stable_sort(Copy.begin(), Copy.end()); });
}
bool skip() const { return Order() == ::Order::Heap; }
std::string name() const {
return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
std::to_string(Quantity);
};
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(Quantities);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,135 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "benchmark/benchmark.h"
#include <new>
#include <vector>
#include <cassert>
struct PointerList {
PointerList* Next = nullptr;
};
struct MallocWrapper {
__attribute__((always_inline))
static void* Allocate(size_t N) {
return std::malloc(N);
}
__attribute__((always_inline))
static void Deallocate(void* P, size_t) {
std::free(P);
}
};
struct NewWrapper {
__attribute__((always_inline))
static void* Allocate(size_t N) {
return ::operator new(N);
}
__attribute__((always_inline))
static void Deallocate(void* P, size_t) {
::operator delete(P);
}
};
struct BuiltinNewWrapper {
__attribute__((always_inline))
static void* Allocate(size_t N) {
return __builtin_operator_new(N);
}
__attribute__((always_inline))
static void Deallocate(void* P, size_t) {
__builtin_operator_delete(P);
}
};
struct BuiltinSizedNewWrapper {
__attribute__((always_inline))
static void* Allocate(size_t N) {
return __builtin_operator_new(N);
}
__attribute__((always_inline))
static void Deallocate(void* P, size_t N) {
__builtin_operator_delete(P, N);
}
};
template <class AllocWrapper>
static void BM_AllocateAndDeallocate(benchmark::State& st) {
const size_t alloc_size = st.range(0);
while (st.KeepRunning()) {
void* p = AllocWrapper::Allocate(alloc_size);
benchmark::DoNotOptimize(p);
AllocWrapper::Deallocate(p, alloc_size);
}
}
template <class AllocWrapper>
static void BM_AllocateOnly(benchmark::State& st) {
const size_t alloc_size = st.range(0);
PointerList *Start = nullptr;
while (st.KeepRunning()) {
PointerList* p = (PointerList*)AllocWrapper::Allocate(alloc_size);
benchmark::DoNotOptimize(p);
p->Next = Start;
Start = p;
}
PointerList *Next = Start;
while (Next) {
PointerList *Tmp = Next;
Next = Tmp->Next;
AllocWrapper::Deallocate(Tmp, alloc_size);
}
}
template <class AllocWrapper>
static void BM_DeallocateOnly(benchmark::State& st) {
const size_t alloc_size = st.range(0);
const auto NumAllocs = st.max_iterations;
std::vector<void*> Pointers(NumAllocs);
for (auto& p : Pointers) {
p = AllocWrapper::Allocate(alloc_size);
}
void** Data = Pointers.data();
void** const End = Pointers.data() + Pointers.size();
while (st.KeepRunning()) {
AllocWrapper::Deallocate(*Data, alloc_size);
Data += 1;
}
assert(Data == End);
}
static int RegisterAllocBenchmarks() {
using FnType = void(*)(benchmark::State&);
struct {
const char* name;
FnType func;
} TestCases[] = {
{"BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>},
{"BM_New", &BM_AllocateAndDeallocate<NewWrapper>},
{"BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>},
{"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>},
{"BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>},
{"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly<BuiltinSizedNewWrapper>},
};
for (auto TC : TestCases) {
benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2);
}
return 0;
}
int Sink = RegisterAllocBenchmarks();
BENCHMARK_MAIN();

View File

@ -0,0 +1,46 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <deque>
#include "benchmark/benchmark.h"
#include "ContainerBenchmarks.h"
#include "GenerateInput.h"
using namespace ContainerBenchmarks;
constexpr std::size_t TestNumInputs = 1024;
BENCHMARK_CAPTURE(BM_ConstructSize,
deque_byte,
std::deque<unsigned char>{})->Arg(5140480);
BENCHMARK_CAPTURE(BM_ConstructSizeValue,
deque_byte,
std::deque<unsigned char>{}, 0)->Arg(5140480);
BENCHMARK_CAPTURE(BM_ConstructIterIter,
deque_char,
std::deque<char>{},
getRandomIntegerInputs<char>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_ConstructIterIter,
deque_size_t,
std::deque<size_t>{},
getRandomIntegerInputs<size_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_ConstructIterIter,
deque_string,
std::deque<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_MAIN();

View File

@ -0,0 +1,232 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <deque>
#include "benchmark/benchmark.h"
namespace {
void run_sizes(auto benchmark) {
benchmark->Arg(0)
->Arg(1)
->Arg(2)
->Arg(64)
->Arg(512)
->Arg(1024)
->Arg(4000)
->Arg(4096)
->Arg(5500)
->Arg(64000)
->Arg(65536)
->Arg(70000);
}
template <class FromContainer, class ToContainer, class Func>
void benchmark_containers(benchmark::State& state, FromContainer& d, ToContainer& v, Func&& func) {
for (auto _ : state) {
benchmark::DoNotOptimize(v);
benchmark::DoNotOptimize(d);
func(d.begin(), d.end(), v.begin());
}
}
template <class Func>
void benchmark_deque_vector(benchmark::State& state, Func&& func) {
auto size = state.range(0);
std::deque<int> d;
d.resize(size);
std::ranges::fill(d, 10);
std::vector<int> v;
v.resize(size);
benchmark_containers(state, d, v, func);
}
template <class Func>
void benchmark_deque_deque(benchmark::State& state, Func&& func) {
auto size = state.range(0);
std::deque<int> d;
d.resize(size);
std::ranges::fill(d, 10);
std::deque<int> v;
v.resize(size);
benchmark_containers(state, d, v, func);
}
template <class Func>
void benchmark_vector_deque(benchmark::State& state, Func&& func) {
auto size = state.range(0);
std::vector<int> d;
d.resize(size);
std::ranges::fill(d, 10);
std::deque<int> v;
v.resize(size);
benchmark_containers(state, d, v, func);
}
template <class FromContainer, class ToContainer, class Func>
void benchmark_containers_backward(benchmark::State& state, FromContainer& d, ToContainer& v, Func&& func) {
for (auto _ : state) {
benchmark::DoNotOptimize(v);
benchmark::DoNotOptimize(d);
func(d.begin(), d.end(), v.end());
}
}
template <class Func>
void benchmark_deque_vector_backward(benchmark::State& state, Func&& func) {
auto size = state.range(0);
std::deque<int> d;
d.resize(size);
std::ranges::fill(d, 10);
std::vector<int> v;
v.resize(size);
benchmark_containers_backward(state, d, v, func);
}
template <class Func>
void benchmark_deque_deque_backward(benchmark::State& state, Func&& func) {
auto size = state.range(0);
std::deque<int> d;
d.resize(size);
std::ranges::fill(d, 10);
std::deque<int> v;
v.resize(size);
benchmark_containers_backward(state, d, v, func);
}
template <class Func>
void benchmark_vector_deque_backward(benchmark::State& state, Func&& func) {
auto size = state.range(0);
std::vector<int> d;
d.resize(size);
std::ranges::fill(d, 10);
std::deque<int> v;
v.resize(size);
benchmark_containers_backward(state, d, v, func);
}
struct CopyFunctor {
template <class... Args>
auto operator()(Args... args) const {
std::copy(std::forward<Args>(args)...);
}
} copy;
struct MoveFunctor {
template <class... Args>
auto operator()(Args... args) const {
std::move(std::forward<Args>(args)...);
}
} move;
struct CopyBackwardFunctor {
template <class... Args>
auto operator()(Args... args) const {
std::copy_backward(std::forward<Args>(args)...);
}
} copy_backward;
struct MoveBackwardFunctor {
template <class... Args>
auto operator()(Args... args) const {
std::move_backward(std::forward<Args>(args)...);
}
} move_backward;
// copy
void BM_deque_vector_copy(benchmark::State& state) { benchmark_deque_vector(state, copy); }
BENCHMARK(BM_deque_vector_copy)->Apply(run_sizes);
void BM_deque_vector_ranges_copy(benchmark::State& state) { benchmark_deque_vector(state, std::ranges::copy); }
BENCHMARK(BM_deque_vector_ranges_copy)->Apply(run_sizes);
void BM_deque_deque_copy(benchmark::State& state) { benchmark_deque_deque(state, copy); }
BENCHMARK(BM_deque_deque_copy)->Apply(run_sizes);
void BM_deque_deque_ranges_copy(benchmark::State& state) { benchmark_deque_deque(state, std::ranges::copy); }
BENCHMARK(BM_deque_deque_ranges_copy)->Apply(run_sizes);
void BM_vector_deque_copy(benchmark::State& state) { benchmark_vector_deque(state, copy); }
BENCHMARK(BM_vector_deque_copy)->Apply(run_sizes);
void BM_vector_deque_ranges_copy(benchmark::State& state) { benchmark_vector_deque(state, std::ranges::copy); }
BENCHMARK(BM_vector_deque_ranges_copy)->Apply(run_sizes);
// move
void BM_deque_vector_move(benchmark::State& state) { benchmark_deque_vector(state, move); }
BENCHMARK(BM_deque_vector_move)->Apply(run_sizes);
void BM_deque_vector_ranges_move(benchmark::State& state) { benchmark_deque_vector(state, std::ranges::move); }
BENCHMARK(BM_deque_vector_ranges_move)->Apply(run_sizes);
void BM_deque_deque_move(benchmark::State& state) { benchmark_deque_deque(state, move); }
BENCHMARK(BM_deque_deque_move)->Apply(run_sizes);
void BM_deque_deque_ranges_move(benchmark::State& state) { benchmark_deque_deque(state, std::ranges::move); }
BENCHMARK(BM_deque_deque_ranges_move)->Apply(run_sizes);
void BM_vector_deque_move(benchmark::State& state) { benchmark_vector_deque(state, move); }
BENCHMARK(BM_vector_deque_move)->Apply(run_sizes);
void BM_vector_deque_ranges_move(benchmark::State& state) { benchmark_vector_deque(state, std::ranges::move); }
BENCHMARK(BM_vector_deque_ranges_move)->Apply(run_sizes);
// copy_backward
void BM_deque_vector_copy_backward(benchmark::State& state) { benchmark_deque_vector_backward(state, copy_backward); }
BENCHMARK(BM_deque_vector_copy_backward)->Apply(run_sizes);
void BM_deque_vector_ranges_copy_backward(benchmark::State& state) {
benchmark_deque_vector_backward(state, std::ranges::copy_backward);
}
BENCHMARK(BM_deque_vector_ranges_copy_backward)->Apply(run_sizes);
void BM_deque_deque_copy_backward(benchmark::State& state) { benchmark_deque_deque_backward(state, copy_backward); }
BENCHMARK(BM_deque_deque_copy_backward)->Apply(run_sizes);
void BM_deque_deque_ranges_copy_backward(benchmark::State& state) {
benchmark_deque_deque_backward(state, std::ranges::copy_backward);
}
BENCHMARK(BM_deque_deque_ranges_copy_backward)->Apply(run_sizes);
void BM_vector_deque_copy_backward(benchmark::State& state) { benchmark_vector_deque_backward(state, copy_backward); }
BENCHMARK(BM_vector_deque_copy_backward)->Apply(run_sizes);
void BM_vector_deque_ranges_copy_backward(benchmark::State& state) {
benchmark_vector_deque_backward(state, std::ranges::copy_backward);
}
BENCHMARK(BM_vector_deque_ranges_copy_backward)->Apply(run_sizes);
// move_backward
void BM_deque_vector_move_backward(benchmark::State& state) { benchmark_deque_vector_backward(state, move_backward); }
BENCHMARK(BM_deque_vector_move_backward)->Apply(run_sizes);
void BM_deque_vector_ranges_move_backward(benchmark::State& state) {
benchmark_deque_vector_backward(state, std::ranges::move_backward);
}
BENCHMARK(BM_deque_vector_ranges_move_backward)->Apply(run_sizes);
void BM_deque_deque_move_backward(benchmark::State& state) { benchmark_deque_deque_backward(state, move_backward); }
BENCHMARK(BM_deque_deque_move_backward)->Apply(run_sizes);
void BM_deque_deque_ranges_move_backward(benchmark::State& state) {
benchmark_deque_deque_backward(state, std::ranges::move_backward);
}
BENCHMARK(BM_deque_deque_ranges_move_backward)->Apply(run_sizes);
void BM_vector_deque_move_backward(benchmark::State& state) { benchmark_vector_deque_backward(state, move_backward); }
BENCHMARK(BM_vector_deque_move_backward)->Apply(run_sizes);
void BM_vector_deque_ranges_move_backward(benchmark::State& state) {
benchmark_vector_deque_backward(state, std::ranges::move_backward);
}
BENCHMARK(BM_vector_deque_ranges_move_backward)->Apply(run_sizes);
} // namespace
BENCHMARK_MAIN();

View File

@ -0,0 +1,163 @@
#include "benchmark/benchmark.h"
#include "GenerateInput.h"
#include "test_iterators.h"
#include "filesystem_include.h"
static const size_t TestNumInputs = 1024;
template <class GenInputs>
void BM_PathConstructString(benchmark::State &st, GenInputs gen) {
using fs::path;
const auto in = gen(st.range(0));
path PP;
for (auto& Part : in)
PP /= Part;
benchmark::DoNotOptimize(PP.native().data());
while (st.KeepRunning()) {
const path P(PP.native());
benchmark::DoNotOptimize(P.native().data());
}
st.SetComplexityN(st.range(0));
}
BENCHMARK_CAPTURE(BM_PathConstructString, large_string,
getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
template <class GenInputs>
void BM_PathConstructCStr(benchmark::State &st, GenInputs gen) {
using fs::path;
const auto in = gen(st.range(0));
path PP;
for (auto& Part : in)
PP /= Part;
benchmark::DoNotOptimize(PP.native().data());
while (st.KeepRunning()) {
const path P(PP.native().c_str());
benchmark::DoNotOptimize(P.native().data());
}
}
BENCHMARK_CAPTURE(BM_PathConstructCStr, large_string,
getRandomStringInputs)->Arg(TestNumInputs);
template <template <class...> class ItType, class GenInputs>
void BM_PathConstructIter(benchmark::State &st, GenInputs gen) {
using fs::path;
using Iter = ItType<std::string::const_iterator>;
const auto in = gen(st.range(0));
path PP;
for (auto& Part : in)
PP /= Part;
auto Start = Iter(PP.native().begin());
auto End = Iter(PP.native().end());
benchmark::DoNotOptimize(PP.native().data());
benchmark::DoNotOptimize(Start);
benchmark::DoNotOptimize(End);
while (st.KeepRunning()) {
const path P(Start, End);
benchmark::DoNotOptimize(P.native().data());
}
st.SetComplexityN(st.range(0));
}
template <class GenInputs>
void BM_PathConstructInputIter(benchmark::State &st, GenInputs gen) {
BM_PathConstructIter<cpp17_input_iterator>(st, gen);
}
template <class GenInputs>
void BM_PathConstructForwardIter(benchmark::State &st, GenInputs gen) {
BM_PathConstructIter<forward_iterator>(st, gen);
}
BENCHMARK_CAPTURE(BM_PathConstructInputIter, large_string,
getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
BENCHMARK_CAPTURE(BM_PathConstructForwardIter, large_string,
getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
template <class GenInputs>
void BM_PathIterateMultipleTimes(benchmark::State &st, GenInputs gen) {
using fs::path;
const auto in = gen(st.range(0));
path PP;
for (auto& Part : in)
PP /= Part;
benchmark::DoNotOptimize(PP.native().data());
while (st.KeepRunning()) {
for (auto const& E : PP) {
benchmark::DoNotOptimize(E.native().data());
}
benchmark::ClobberMemory();
}
st.SetComplexityN(st.range(0));
}
BENCHMARK_CAPTURE(BM_PathIterateMultipleTimes, iterate_elements,
getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
template <class GenInputs>
void BM_PathIterateOnce(benchmark::State &st, GenInputs gen) {
using fs::path;
const auto in = gen(st.range(0));
path PP;
for (auto& Part : in)
PP /= Part;
benchmark::DoNotOptimize(PP.native().data());
while (st.KeepRunning()) {
const path P = PP.native();
for (auto const& E : P) {
benchmark::DoNotOptimize(E.native().data());
}
benchmark::ClobberMemory();
}
st.SetComplexityN(st.range(0));
}
BENCHMARK_CAPTURE(BM_PathIterateOnce, iterate_elements,
getRandomStringInputs)->Range(8, TestNumInputs)->Complexity();
template <class GenInputs>
void BM_PathIterateOnceBackwards(benchmark::State &st, GenInputs gen) {
using fs::path;
const auto in = gen(st.range(0));
path PP;
for (auto& Part : in)
PP /= Part;
benchmark::DoNotOptimize(PP.native().data());
while (st.KeepRunning()) {
const path P = PP.native();
const auto B = P.begin();
auto I = P.end();
while (I != B) {
--I;
benchmark::DoNotOptimize(*I);
}
benchmark::DoNotOptimize(*I);
}
}
BENCHMARK_CAPTURE(BM_PathIterateOnceBackwards, iterate_elements,
getRandomStringInputs)->Arg(TestNumInputs);
static fs::path getRandomPaths(int NumParts, int PathLen) {
fs::path Result;
while (NumParts--) {
std::string Part = getRandomString(PathLen);
Result /= Part;
}
return Result;
}
template <class GenInput>
void BM_LexicallyNormal(benchmark::State &st, GenInput gen, size_t PathLen) {
using fs::path;
auto In = gen(st.range(0), PathLen);
benchmark::DoNotOptimize(&In);
while (st.KeepRunning()) {
benchmark::DoNotOptimize(In.lexically_normal());
}
st.SetComplexityN(st.range(0));
}
BENCHMARK_CAPTURE(BM_LexicallyNormal, small_path,
getRandomPaths, /*PathLen*/5)->RangeMultiplier(2)->Range(2, 256)->Complexity();
BENCHMARK_CAPTURE(BM_LexicallyNormal, large_path,
getRandomPaths, /*PathLen*/32)->RangeMultiplier(2)->Range(2, 256)->Complexity();
BENCHMARK_MAIN();

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <format>
#include <string>
#include "benchmark/benchmark.h"
#include "make_string.h"
#define CSTR(S) MAKE_CSTRING(CharT, S)
template <class CharT>
static void BM_format_string(benchmark::State& state) {
size_t size = state.range(0);
std::basic_string<CharT> str(size, CharT('*'));
while (state.KeepRunningBatch(str.size()))
benchmark::DoNotOptimize(std::format(CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
BENCHMARK_TEMPLATE(BM_format_string, char)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_string, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,107 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <format>
#include <iterator>
#include <algorithm>
#include <array>
#include <list>
#include <span>
#include <string>
#include <vector>
#include "benchmark/benchmark.h"
#include "make_string.h"
#define CSTR(S) MAKE_CSTRING(CharT, S)
/*** Back inserter ***/
template <class Container>
static void BM_format_to_string_back_inserter(benchmark::State& state) {
using CharT = typename Container::value_type;
size_t size = state.range(0);
auto str = std::basic_string<CharT>(size, CharT('*'));
for (auto _ : state) {
Container output;
benchmark::DoNotOptimize(std::format_to(std::back_inserter(output), CSTR("{}"), str));
}
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
/*** Begin ***/
template <class Container>
static void BM_format_to_string_begin(benchmark::State& state) {
using CharT = typename Container::value_type;
size_t size = state.range(0);
auto str = std::basic_string<CharT>(size, CharT('*'));
Container output(size, CharT('-'));
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to(std::begin(output), CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
/*** Pointer ***/
template <class CharT>
static void BM_format_to_string_span(benchmark::State& state) {
size_t size = state.range(0);
auto str = std::basic_string<CharT>(size, CharT('*'));
auto buffer = std::basic_string<CharT>(size, CharT('-'));
std::span<CharT> output{buffer};
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to(std::begin(output), CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
template <class CharT>
static void BM_format_to_string_pointer(benchmark::State& state) {
size_t size = state.range(0);
auto str = std::basic_string<CharT>(size, CharT('*'));
auto buffer = std::basic_string<CharT>(size, CharT('-'));
CharT* output = buffer.data();
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to(output, CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
/*** Main ***/
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_span, char)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_pointer, char)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_back_inserter, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_begin, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_span, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_string_pointer, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,107 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <format>
#include <iterator>
#include <algorithm>
#include <array>
#include <list>
#include <span>
#include <string>
#include <vector>
#include "benchmark/benchmark.h"
#include "make_string.h"
#define CSTR(S) MAKE_CSTRING(CharT, S)
/*** Back inserter ***/
template <class Container>
static void BM_format_to_n_string_back_inserter(benchmark::State& state) {
using CharT = typename Container::value_type;
size_t size = state.range(0);
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
for (auto _ : state) {
Container output;
benchmark::DoNotOptimize(std::format_to_n(std::back_inserter(output), size, CSTR("{}"), str));
}
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
/*** Begin ***/
template <class Container>
static void BM_format_to_n_string_begin(benchmark::State& state) {
using CharT = typename Container::value_type;
size_t size = state.range(0);
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
Container output(size, CharT('-'));
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to_n(std::begin(output), size, CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
/*** Pointer ***/
template <class CharT>
static void BM_format_to_n_string_span(benchmark::State& state) {
size_t size = state.range(0);
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
auto buffer = std::basic_string<CharT>(size, CharT('-'));
std::span<CharT> output{buffer};
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to_n(std::begin(output), size, CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
template <class CharT>
static void BM_format_to_n_string_pointer(benchmark::State& state) {
size_t size = state.range(0);
auto str = std::basic_string<CharT>(2 * size, CharT('*'));
auto buffer = std::basic_string<CharT>(size, CharT('-'));
CharT* output = buffer.data();
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to_n(output, size, CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
/*** Main ***/
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::string)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::vector<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::list<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_span, char)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_pointer, char)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_back_inserter, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::wstring)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::vector<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_begin, std::list<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_span, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_format_to_n_string_pointer, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <format>
#include <string>
#include "benchmark/benchmark.h"
#include "make_string.h"
#define CSTR(S) MAKE_CSTRING(CharT, S)
template <class CharT>
static void BM_formatted_size_string(benchmark::State& state) {
size_t size = state.range(0);
std::basic_string<CharT> str(size, CharT('*'));
while (state.KeepRunningBatch(str.size()))
benchmark::DoNotOptimize(std::formatted_size(CSTR("{}"), str));
state.SetBytesProcessed(state.iterations() * size * sizeof(CharT));
}
BENCHMARK_TEMPLATE(BM_formatted_size_string, char)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK_TEMPLATE(BM_formatted_size_string, wchar_t)->RangeMultiplier(2)->Range(1, 1 << 20);
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,251 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <format>
#include <array>
#include <limits>
#include <random>
#include <string>
#include "CartesianBenchmarks.h"
#include "benchmark/benchmark.h"
// *** Localization ***
enum class LocalizationE { False, True };
struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
};
template <LocalizationE E>
struct Localization {};
template <>
struct Localization<LocalizationE::False> {
static constexpr const char* fmt = "";
};
template <>
struct Localization<LocalizationE::True> {
static constexpr const char* fmt = "L";
};
// *** Types ***
enum class TypeE { Float, Double, LongDouble };
// TODO FMT Set to 3 after to_chars has long double suport.
struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
static constexpr const char* Names[] = {"Float", "Double", "LongDouble"};
};
template <TypeE E>
struct Type {};
template <>
struct Type<TypeE::Float> {
using type = float;
};
template <>
struct Type<TypeE::Double> {
using type = double;
};
template <>
struct Type<TypeE::LongDouble> {
using type = long double;
};
// *** Values ***
enum class ValueE { Inf, Random };
struct AllValues : EnumValuesAsTuple<AllValues, ValueE, 2> {
static constexpr const char* Names[] = {"Inf", "Random"};
};
template <ValueE E>
struct Value {};
template <>
struct Value<ValueE::Inf> {
template <class F>
static std::array<F, 1000> make_data() {
std::array<F, 1000> result;
std::fill(result.begin(), result.end(), -std::numeric_limits<F>::infinity());
return result;
}
};
template <>
struct Value<ValueE::Random> {
template <class F>
static std::array<F, 1000> make_data() {
std::random_device seed;
std::mt19937 generator(seed());
std::uniform_int_distribution<std::conditional_t<sizeof(F) == sizeof(uint32_t), uint32_t, uint64_t>> distribution;
std::array<F, 1000> result;
std::generate(result.begin(), result.end(), [&] {
while (true) {
auto result = std::bit_cast<F>(distribution(generator));
if (std::isfinite(result))
return result;
}
});
return result;
}
};
// *** Display Type ***
enum class DisplayTypeE {
Default,
Hex,
Scientific,
Fixed,
General,
};
struct AllDisplayTypes : EnumValuesAsTuple<AllDisplayTypes, DisplayTypeE, 5> {
static constexpr const char* Names[] = {"DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed",
"DisplayGeneral"};
};
template <DisplayTypeE E>
struct DisplayType {};
template <>
struct DisplayType<DisplayTypeE::Default> {
static constexpr const char* fmt = "";
};
template <>
struct DisplayType<DisplayTypeE::Hex> {
static constexpr const char* fmt = "a";
};
template <>
struct DisplayType<DisplayTypeE::Scientific> {
static constexpr const char* fmt = "e";
};
template <>
struct DisplayType<DisplayTypeE::Fixed> {
static constexpr const char* fmt = "f";
};
template <>
struct DisplayType<DisplayTypeE::General> {
static constexpr const char* fmt = "g";
};
// *** Alignment ***
enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
static constexpr const char* Names[] = {"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight",
"ZeroPadding"};
};
template <AlignmentE E>
struct Alignment {};
template <>
struct Alignment<AlignmentE::None> {
static constexpr const char* fmt = "";
};
template <>
struct Alignment<AlignmentE::Left> {
// Width > PrecisionE::Huge
static constexpr const char* fmt = "0<17500";
};
template <>
struct Alignment<AlignmentE::Center> {
// Width > PrecisionE::Huge
static constexpr const char* fmt = "0^17500";
};
template <>
struct Alignment<AlignmentE::Right> {
// Width > PrecisionE::Huge
static constexpr const char* fmt = "0>17500";
};
template <>
struct Alignment<AlignmentE::ZeroPadding> {
// Width > PrecisionE::Huge
static constexpr const char* fmt = "017500";
};
enum class PrecisionE { None, Zero, Small, Huge };
struct AllPrecisions : EnumValuesAsTuple<AllPrecisions, PrecisionE, 4> {
static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"};
};
template <PrecisionE E>
struct Precision {};
template <>
struct Precision<PrecisionE::None> {
static constexpr const char* fmt = "";
};
template <>
struct Precision<PrecisionE::Zero> {
static constexpr const char* fmt = ".0";
};
template <>
struct Precision<PrecisionE::Small> {
static constexpr const char* fmt = ".10";
};
template <>
struct Precision<PrecisionE::Huge> {
// The maximum precision for a minimal sub normal long double is +/- 0x1p-16494.
// This value is always larger than that value forcing the trailing zero path
// to be executed.
static constexpr const char* fmt = ".17000";
};
template <class L, class DT, class T, class V, class A, class P>
struct FloatingPoint {
using F = typename Type<T::value>::type;
void run(benchmark::State& state) const {
std::array<F, 1000> data{Value<V::value>::template make_data<F>()};
std::array<char, 20'000> output;
while (state.KeepRunningBatch(1000))
for (F value : data)
benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
}
std::string name() const {
return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();
}
static constexpr std::string make_fmt() {
return std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt + Localization<L::value>::fmt +
DisplayType<DT::value>::fmt + "}";
}
static constexpr auto fmt = []() {
constexpr size_t s = make_fmt().size();
std::array<char, s> r;
std::ranges::copy(make_fmt(), r.begin());
return r;
}();
};
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<FloatingPoint, AllLocalizations, AllDisplayTypes, AllTypes, AllValues, AllAlignments,
AllPrecisions>();
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,208 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <array>
#include <format>
#include <random>
#include "benchmark/benchmark.h"
#include "CartesianBenchmarks.h"
// Tests the full range of the value.
template <class T>
static std::array<T, 1000>
generate(std::uniform_int_distribution<T> distribution = std::uniform_int_distribution<T>{
std::numeric_limits<T>::min(), std::numeric_limits<T>::max()}) {
std::mt19937 generator;
std::array<T, 1000> result;
std::generate_n(result.begin(), result.size(), [&] { return distribution(generator); });
return result;
}
template <class T>
static void BM_Basic(benchmark::State& state) {
std::array data{generate<T>()};
std::array<char, 100> output;
while (state.KeepRunningBatch(data.size()))
for (auto value : data)
benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
}
BENCHMARK_TEMPLATE(BM_Basic, uint32_t);
BENCHMARK_TEMPLATE(BM_Basic, int32_t);
BENCHMARK_TEMPLATE(BM_Basic, uint64_t);
BENCHMARK_TEMPLATE(BM_Basic, int64_t);
// Ideally the low values of a 128-bit value are all dispatched to a 64-bit routine.
template <class T>
static void BM_BasicLow(benchmark::State& state) {
using U = std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>;
std::array data{
generate<T>(std::uniform_int_distribution<T>{std::numeric_limits<U>::min(), std::numeric_limits<U>::max()})};
std::array<char, 100> output;
while (state.KeepRunningBatch(data.size()))
for (auto value : data)
benchmark::DoNotOptimize(std::format_to(output.begin(), "{}", value));
}
BENCHMARK_TEMPLATE(BM_BasicLow, __uint128_t);
BENCHMARK_TEMPLATE(BM_BasicLow, __int128_t);
BENCHMARK_TEMPLATE(BM_Basic, __uint128_t);
BENCHMARK_TEMPLATE(BM_Basic, __int128_t);
// *** Localization ***
enum class LocalizationE { False, True };
struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
};
template <LocalizationE E>
struct Localization {};
template <>
struct Localization<LocalizationE::False> {
static constexpr const char* fmt = "";
};
template <>
struct Localization<LocalizationE::True> {
static constexpr const char* fmt = "L";
};
// *** Base ***
enum class BaseE {
Binary,
Octal,
Decimal,
Hex,
HexUpper,
};
struct AllBases : EnumValuesAsTuple<AllBases, BaseE, 5> {
static constexpr const char* Names[] = {"BaseBin", "BaseOct", "BaseDec", "BaseHex", "BaseHexUpper"};
};
template <BaseE E>
struct Base {};
template <>
struct Base<BaseE::Binary> {
static constexpr const char* fmt = "b";
};
template <>
struct Base<BaseE::Octal> {
static constexpr const char* fmt = "o";
};
template <>
struct Base<BaseE::Decimal> {
static constexpr const char* fmt = "d";
};
template <>
struct Base<BaseE::Hex> {
static constexpr const char* fmt = "x";
};
template <>
struct Base<BaseE::HexUpper> {
static constexpr const char* fmt = "X";
};
// *** Types ***
enum class TypeE { Int64, Uint64 };
struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
static constexpr const char* Names[] = {"Int64", "Uint64"};
};
template <TypeE E>
struct Type {};
template <>
struct Type<TypeE::Int64> {
using type = int64_t;
static std::array<type, 1000> make_data() { return generate<type>(); }
};
template <>
struct Type<TypeE::Uint64> {
using type = uint64_t;
static std::array<type, 1000> make_data() { return generate<type>(); }
};
// *** Alignment ***
enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
static constexpr const char* Names[] = {
"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"};
};
template <AlignmentE E>
struct Alignment {};
template <>
struct Alignment<AlignmentE::None> {
static constexpr const char* fmt = "";
};
template <>
struct Alignment<AlignmentE::Left> {
static constexpr const char* fmt = "0<512";
};
template <>
struct Alignment<AlignmentE::Center> {
static constexpr const char* fmt = "0^512";
};
template <>
struct Alignment<AlignmentE::Right> {
static constexpr const char* fmt = "0>512";
};
template <>
struct Alignment<AlignmentE::ZeroPadding> {
static constexpr const char* fmt = "0512";
};
template <class L, class B, class T, class A>
struct Integral {
void run(benchmark::State& state) const {
std::array data{Type<T::value>::make_data()};
std::array<char, 512> output;
while (state.KeepRunningBatch(data.size()))
for (auto value : data)
benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
}
std::string name() const { return "Integral" + L::name() + B::name() + A::name() + T::name(); }
static constexpr std::string make_fmt() {
return std::string("{:") + Alignment<A::value>::fmt + Localization<L::value>::fmt + Base<B::value>::fmt + "}";
}
static constexpr auto fmt = []() {
constexpr size_t s = make_fmt().size();
std::array<char, s> r;
std::ranges::copy(make_fmt(), r.begin());
return r;
}();
};
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<Integral, AllLocalizations, AllBases, AllTypes, AllAlignments>();
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,231 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include "CartesianBenchmarks.h"
#include "benchmark/benchmark.h"
#include "test_macros.h"
namespace {
enum class FunctionType {
Null,
FunctionPointer,
MemberFunctionPointer,
MemberPointer,
SmallTrivialFunctor,
SmallNonTrivialFunctor,
LargeTrivialFunctor,
LargeNonTrivialFunctor
};
struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
static constexpr const char* Names[] = {"Null",
"FuncPtr",
"MemFuncPtr",
"MemPtr",
"SmallTrivialFunctor",
"SmallNonTrivialFunctor",
"LargeTrivialFunctor",
"LargeNonTrivialFunctor"};
};
enum class Opacity { kOpaque, kTransparent };
struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
static constexpr const char* Names[] = {"Opaque", "Transparent"};
};
struct S {
int function() const { return 0; }
int field = 0;
};
int FunctionWithS(const S*) { return 0; }
struct SmallTrivialFunctor {
int operator()(const S*) const { return 0; }
};
struct SmallNonTrivialFunctor {
SmallNonTrivialFunctor() {}
SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
~SmallNonTrivialFunctor() {}
int operator()(const S*) const { return 0; }
};
struct LargeTrivialFunctor {
LargeTrivialFunctor() {
// Do not spend time initializing the padding.
}
int padding[16];
int operator()(const S*) const { return 0; }
};
struct LargeNonTrivialFunctor {
int padding[16];
LargeNonTrivialFunctor() {
// Do not spend time initializing the padding.
}
LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
~LargeNonTrivialFunctor() {}
int operator()(const S*) const { return 0; }
};
using Function = std::function<int(const S*)>;
TEST_ALWAYS_INLINE
inline Function MakeFunction(FunctionType type, bool opaque = false) {
switch (type) {
case FunctionType::Null:
return nullptr;
case FunctionType::FunctionPointer:
return maybeOpaque(FunctionWithS, opaque);
case FunctionType::MemberFunctionPointer:
return maybeOpaque(&S::function, opaque);
case FunctionType::MemberPointer:
return maybeOpaque(&S::field, opaque);
case FunctionType::SmallTrivialFunctor:
return maybeOpaque(SmallTrivialFunctor{}, opaque);
case FunctionType::SmallNonTrivialFunctor:
return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
case FunctionType::LargeTrivialFunctor:
return maybeOpaque(LargeTrivialFunctor{}, opaque);
case FunctionType::LargeNonTrivialFunctor:
return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
}
}
template <class Opacity, class FunctionType>
struct ConstructAndDestroy {
static void run(benchmark::State& state) {
for (auto _ : state) {
if (Opacity() == ::Opacity::kOpaque) {
benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
} else {
MakeFunction(FunctionType());
}
}
}
static std::string name() {
return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
}
};
template <class FunctionType>
struct Copy {
static void run(benchmark::State& state) {
auto value = MakeFunction(FunctionType());
for (auto _ : state) {
benchmark::DoNotOptimize(value);
auto copy = value; // NOLINT
benchmark::DoNotOptimize(copy);
}
}
static std::string name() { return "BM_Copy" + FunctionType::name(); }
};
template <class FunctionType>
struct Move {
static void run(benchmark::State& state) {
Function values[2] = {MakeFunction(FunctionType())};
int i = 0;
for (auto _ : state) {
benchmark::DoNotOptimize(values);
benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
i ^= 1;
}
}
static std::string name() {
return "BM_Move" + FunctionType::name();
}
};
template <class Function1, class Function2>
struct Swap {
static void run(benchmark::State& state) {
Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
for (auto _ : state) {
benchmark::DoNotOptimize(values);
values[0].swap(values[1]);
}
}
static bool skip() { return Function1() > Function2(); }
static std::string name() {
return "BM_Swap" + Function1::name() + Function2::name();
}
};
template <class FunctionType>
struct OperatorBool {
static void run(benchmark::State& state) {
auto f = MakeFunction(FunctionType());
for (auto _ : state) {
benchmark::DoNotOptimize(f);
benchmark::DoNotOptimize(static_cast<bool>(f));
}
}
static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
};
template <class FunctionType>
struct Invoke {
static void run(benchmark::State& state) {
S s;
const auto value = MakeFunction(FunctionType());
for (auto _ : state) {
benchmark::DoNotOptimize(value);
benchmark::DoNotOptimize(value(&s));
}
}
static bool skip() { return FunctionType() == ::FunctionType::Null; }
static std::string name() { return "BM_Invoke" + FunctionType::name(); }
};
template <class FunctionType>
struct InvokeInlined {
static void run(benchmark::State& state) {
S s;
for (auto _ : state) {
MakeFunction(FunctionType())(&s);
}
}
static bool skip() { return FunctionType() == ::FunctionType::Null; }
static std::string name() {
return "BM_InvokeInlined" + FunctionType::name();
}
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
AllFunctionTypes>();
makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
makeCartesianProductBenchmark<Move, AllFunctionTypes>();
makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <deque>
#include <ranges>
#include "benchmark/benchmark.h"
namespace {
void run_sizes(auto benchmark) {
benchmark->Arg(0)
->Arg(1)
->Arg(2)
->Arg(64)
->Arg(512)
->Arg(1024)
->Arg(4000)
->Arg(4096)
->Arg(5500)
->Arg(64000)
->Arg(65536)
->Arg(70000);
}
void BM_join_view_in_vectors(benchmark::State& state) {
auto size = state.range(0);
std::vector<std::vector<int>> input(size, std::vector<int>(32));
std::ranges::fill(input | std::views::join, 10);
std::vector<int> output;
output.resize(size * 32);
for (auto _ : state) {
benchmark::DoNotOptimize(input);
benchmark::DoNotOptimize(output);
std::ranges::copy(input | std::views::join, output.begin());
}
}
BENCHMARK(BM_join_view_in_vectors)->Apply(run_sizes);
void BM_join_view_out_vectors(benchmark::State& state) {
auto size = state.range(0);
std::vector<std::vector<int>> output(size, std::vector<int>(32));
std::vector<int> input;
input.resize(size * 32);
std::ranges::fill(input, 10);
for (auto _ : state) {
benchmark::DoNotOptimize(output);
benchmark::DoNotOptimize(input);
std::ranges::copy(input, (output | std::views::join).begin());
}
}
BENCHMARK(BM_join_view_out_vectors)->Apply(run_sizes);
void BM_join_view_deques(benchmark::State& state) {
auto size = state.range(0);
std::deque<std::deque<int>> deque(size, std::deque<int>(32));
std::ranges::fill(deque | std::views::join, 10);
std::vector<int> output;
output.resize(size * 32);
for (auto _ : state) {
benchmark::DoNotOptimize(deque);
benchmark::DoNotOptimize(output);
std::ranges::copy(deque | std::views::join, output.begin());
}
}
BENCHMARK(BM_join_view_deques)->Apply(run_sizes);
} // namespace
BENCHMARK_MAIN();

View File

@ -0,0 +1,23 @@
# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
# Configuration file for the 'lit' test runner.
import os
import site
site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'utils'))
from libcxx.test.googlebenchmark import GoogleBenchmark
# Tell pylint that we know config and lit_config exist somewhere.
if 'PYLINT_IMPORT' in os.environ:
config = object()
lit_config = object()
# name: The name of this test suite.
config.name = 'libc++ benchmarks'
config.suffixes = []
config.test_exec_root = os.path.join(config.libcxx_obj_root, 'benchmarks')
config.test_source_root = config.test_exec_root
config.test_format = GoogleBenchmark(test_sub_dirs='.',
test_suffix='.libcxx.out',
benchmark_args=config.benchmark_args)

View File

@ -0,0 +1,10 @@
@LIT_SITE_CFG_IN_HEADER@
import sys
config.libcxx_src_root = "@LIBCXX_SOURCE_DIR@"
config.libcxx_obj_root = "@LIBCXX_BINARY_DIR@"
config.benchmark_args = "@LIBCXX_BENCHMARK_TEST_ARGS@".split(';')
# Let the main config do the real work.
lit_config.load_config(config, "@LIBCXX_SOURCE_DIR@/benchmarks/lit.cfg.py")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <list>
#include <memory_resource>
#include "benchmark/benchmark.h"
static void bm_list(benchmark::State& state) {
char buffer[16384];
std::pmr::monotonic_buffer_resource resource(buffer, sizeof(buffer));
for (auto _ : state) {
std::pmr::list<int> l(&resource);
for (size_t i = 0; i != state.range(); ++i) {
l.push_back(1);
benchmark::DoNotOptimize(l);
}
resource.release();
}
}
BENCHMARK(bm_list)->Range(1, 2048);
BENCHMARK_MAIN();

View File

@ -0,0 +1,248 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <cstdint>
#include <memory>
#include <random>
#include <set>
#include <string>
#include <vector>
#include "CartesianBenchmarks.h"
#include "benchmark/benchmark.h"
#include "test_macros.h"
namespace {
enum class HitType { Hit, Miss };
struct AllHitTypes : EnumValuesAsTuple<AllHitTypes, HitType, 2> {
static constexpr const char* Names[] = {"Hit", "Miss"};
};
enum class AccessPattern { Ordered, Random };
struct AllAccessPattern
: EnumValuesAsTuple<AllAccessPattern, AccessPattern, 2> {
static constexpr const char* Names[] = {"Ordered", "Random"};
};
void sortKeysBy(std::vector<uint64_t>& Keys, AccessPattern AP) {
if (AP == AccessPattern::Random) {
std::random_device R;
std::mt19937 M(R());
std::shuffle(std::begin(Keys), std::end(Keys), M);
}
}
struct TestSets {
std::vector<std::set<uint64_t> > Sets;
std::vector<uint64_t> Keys;
};
TestSets makeTestingSets(size_t TableSize, size_t NumTables, HitType Hit,
AccessPattern Access) {
TestSets R;
R.Sets.resize(1);
for (uint64_t I = 0; I < TableSize; ++I) {
R.Sets[0].insert(2 * I);
R.Keys.push_back(Hit == HitType::Hit ? 2 * I : 2 * I + 1);
}
R.Sets.resize(NumTables, R.Sets[0]);
sortKeysBy(R.Keys, Access);
return R;
}
struct Base {
size_t TableSize;
size_t NumTables;
Base(size_t T, size_t N) : TableSize(T), NumTables(N) {}
bool skip() const {
size_t Total = TableSize * NumTables;
return Total < 100 || Total > 1000000;
}
std::string baseName() const {
return "_TableSize" + std::to_string(TableSize) + "_NumTables" +
std::to_string(NumTables);
}
};
template <class Access>
struct Create : Base {
using Base::Base;
void run(benchmark::State& State) const {
std::vector<uint64_t> Keys(TableSize);
std::iota(Keys.begin(), Keys.end(), uint64_t{0});
sortKeysBy(Keys, Access());
while (State.KeepRunningBatch(TableSize * NumTables)) {
std::vector<std::set<uint64_t>> Sets(NumTables);
for (auto K : Keys) {
for (auto& Set : Sets) {
benchmark::DoNotOptimize(Set.insert(K));
}
}
}
}
std::string name() const {
return "BM_Create" + Access::name() + baseName();
}
};
template <class Hit, class Access>
struct Find : Base {
using Base::Base;
void run(benchmark::State& State) const {
auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access());
while (State.KeepRunningBatch(TableSize * NumTables)) {
for (auto K : Data.Keys) {
for (auto& Set : Data.Sets) {
benchmark::DoNotOptimize(Set.find(K));
}
}
}
}
std::string name() const {
return "BM_Find" + Hit::name() + Access::name() + baseName();
}
};
template <class Hit, class Access>
struct FindNeEnd : Base {
using Base::Base;
void run(benchmark::State& State) const {
auto Data = makeTestingSets(TableSize, NumTables, Hit(), Access());
while (State.KeepRunningBatch(TableSize * NumTables)) {
for (auto K : Data.Keys) {
for (auto& Set : Data.Sets) {
benchmark::DoNotOptimize(Set.find(K) != Set.end());
}
}
}
}
std::string name() const {
return "BM_FindNeEnd" + Hit::name() + Access::name() + baseName();
}
};
template <class Access>
struct InsertHit : Base {
using Base::Base;
void run(benchmark::State& State) const {
auto Data = makeTestingSets(TableSize, NumTables, HitType::Hit, Access());
while (State.KeepRunningBatch(TableSize * NumTables)) {
for (auto K : Data.Keys) {
for (auto& Set : Data.Sets) {
benchmark::DoNotOptimize(Set.insert(K));
}
}
}
}
std::string name() const {
return "BM_InsertHit" + Access::name() + baseName();
}
};
template <class Access>
struct InsertMissAndErase : Base {
using Base::Base;
void run(benchmark::State& State) const {
auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss, Access());
while (State.KeepRunningBatch(TableSize * NumTables)) {
for (auto K : Data.Keys) {
for (auto& Set : Data.Sets) {
benchmark::DoNotOptimize(Set.erase(Set.insert(K).first));
}
}
}
}
std::string name() const {
return "BM_InsertMissAndErase" + Access::name() + baseName();
}
};
struct IterateRangeFor : Base {
using Base::Base;
void run(benchmark::State& State) const {
auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss,
AccessPattern::Ordered);
while (State.KeepRunningBatch(TableSize * NumTables)) {
for (auto& Set : Data.Sets) {
for (auto& V : Set) {
benchmark::DoNotOptimize(V);
}
}
}
}
std::string name() const { return "BM_IterateRangeFor" + baseName(); }
};
struct IterateBeginEnd : Base {
using Base::Base;
void run(benchmark::State& State) const {
auto Data = makeTestingSets(TableSize, NumTables, HitType::Miss,
AccessPattern::Ordered);
while (State.KeepRunningBatch(TableSize * NumTables)) {
for (auto& Set : Data.Sets) {
for (auto it = Set.begin(); it != Set.end(); ++it) {
benchmark::DoNotOptimize(*it);
}
}
}
}
std::string name() const { return "BM_IterateBeginEnd" + baseName(); }
};
} // namespace
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
const std::vector<size_t> TableSize{1, 10, 100, 1000, 10000, 100000, 1000000};
const std::vector<size_t> NumTables{1, 10, 100, 1000, 10000, 100000, 1000000};
makeCartesianProductBenchmark<Create, AllAccessPattern>(TableSize, NumTables);
makeCartesianProductBenchmark<Find, AllHitTypes, AllAccessPattern>(
TableSize, NumTables);
makeCartesianProductBenchmark<FindNeEnd, AllHitTypes, AllAccessPattern>(
TableSize, NumTables);
makeCartesianProductBenchmark<InsertHit, AllAccessPattern>(
TableSize, NumTables);
makeCartesianProductBenchmark<InsertMissAndErase, AllAccessPattern>(
TableSize, NumTables);
makeCartesianProductBenchmark<IterateRangeFor>(TableSize, NumTables);
makeCartesianProductBenchmark<IterateBeginEnd>(TableSize, NumTables);
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <array>
#include <cstddef>
#include <functional>
#include <random>
#include "benchmark/benchmark.h"
constexpr std::size_t MAX_BUFFER_LEN = 256;
constexpr std::size_t MAX_SEED_LEN = 16;
static void BM_SeedSeq_Generate(benchmark::State& state) {
std::array<std::uint32_t, MAX_BUFFER_LEN> buffer;
std::array<std::uint32_t, MAX_SEED_LEN> seeds;
{
std::random_device rd;
std::generate(std::begin(seeds), std::begin(seeds) + state.range(0), [&]() { return rd(); });
}
std::seed_seq seed(std::begin(seeds), std::begin(seeds) + state.range(0));
for (auto _ : state) {
seed.generate(std::begin(buffer), std::begin(buffer) + state.range(1));
}
}
BENCHMARK(BM_SeedSeq_Generate)->Ranges({{1, MAX_SEED_LEN}, {1, MAX_BUFFER_LEN}});
BENCHMARK_MAIN();

View File

@ -0,0 +1,300 @@
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_HAS_NO_UNICODE
# include <format>
# include <string_view>
# include "benchmark/benchmark.h"
# include "make_string.h"
# define SV(S) MAKE_STRING_VIEW(CharT, S)
// generated with https://generator.lorem-ipsum.info/_latin
template <class CharT>
std::basic_string_view<CharT> ascii_text() {
return SV(
R"( Lorem ipsum dolor sit amet, ne sensibus evertitur aliquando his.
Iuvaret fabulas qui ex, ex iriure iisque nostrum mea. Solum
pericula qui ad. Elitr oporteat ius ad.
Quas rationibus ad mel. Appellantur intellegebat ad mei, ius audire volumus
consectetuer id. Ei sit definitionem mediocritatem, vim indoctum intellegat id,
dicta laboramus instructior in vix. Mel an quando malorum, id vis mollis
invidunt, placerat maiestatis comprehensam ut cum. Suas regione interesset id
per, et docendi accumsan has, autem atomorum est te.
Cu debitis ancillae sea, alii definitiones ex cum, vim no erat antiopam. Eam et
unum quas scriptorem. An bonorum elaboraret complectitur nam, vim ei persecuti
democritum mediocritatem. Suscipit platonem signiferumque ei cum, in sale
volutpat ocurreret vel. Te vel nihil nominavi adipiscing, stet ancillae mel ea.
Sit detraxit menandri platonem ea, cum at tale viris virtute.
Regione detraxit gloriatur sit eu, sonet labitur sententiae et pro, at sit
alterum aliquid interpretaris. Sonet voluptua duo id, vix ea accumsan
liberavisse. Nam id commune probatus contentiones. Et zril dolore laudem duo,
ea usu mollis melius referrentur, vel ex case consequuntur. Id nam illum mollis
ponderum. Quis tamquam ullamcorper sed ne, legimus vituperatoribus est id.
Et eum probo consulatu. At eos errem aliquando theophrastus, sea ad eius omnis.
No vis iusto scriptorem adversarium, dicat viderer ea sit. Et veri euripidis
sea, justo putent iudicabit vim id. Sea suas tincidunt vituperatoribus in. Ne
eam aeterno sensibus concludaturque, solet legere his id, usu ei dicat
dissentiunt. Est et autem erant.
Per quod laboramus an. Dico voluptua at mea, an animal minimum eum. Pri an
option salutatus, causae feugiat menandri an sed. Voluptaria dissentiet vix ut,
alii solet te quo, in facer ceteros eos. Ad nibh meis percipitur sit,
aliquam molestie cu vis, iisque malorum interesset et eos.
Eos in feugiat insolens abhorreant. Ea tale esse alienum has, mel et saperet
appellantur, aliquip salutandi deterruisset ut mel. Eos ei quod simul
interpretaris, aeque elitr putent per at, et veri eripuit ceteros his. Cu pro
meis aperiam volutpat, ex alterum scripserit ius, scriptorem deterruisset eu
qui. Graeco debitis lobortis cu mea.
Alii corpora id ius, cu quo oblique eloquentiam. Et duis civibus atomorum sea,
veniam utroque scriptorem vim cu. Ut oratio eruditi mediocritatem est. Amet
nibh dolore mea ea, tollit laoreet eligendi qui ex, cu essent forensibus
his.
Usu ex ipsum apeirian, eos congue scripserit omittantur et. Ea eum persecuti
deseruisse, probatus torquatos est no, in has mutat mundi dolorem. Albucius
sensibus ex cum. Ferri virtute referrentur an per, est choro option bonorum ex.
Quando accusam vis te, tale mazim et pro. Magna dolorem tincidunt
nec te, albucius adipisci ad pri. Magna facilisi adipisci at usu, et vel
dissentiunt neglegentur, prima audiam vocibus an duo. Enim detracto te sea, mel
quis dicit gubergren ex, iusto adversarium consequuntur per ne.
)");
}
template <class CharT>
std::basic_string_view<CharT> unicode_text() {
return SV(
R"(Lōrem ipsūm dolor sīt æmeÞ, ea vel nostrud feuġǣit, muciūs tēmporiȝus
refērrēnÞur no mel, quo placērǽt consecÞetuer . Veri soƿet euripīðis id has,
sumo paulō dissentias duo , dētrāxīt neglēgeƿtur prī. Sēd option oporÞerē
no. Nec ēū nēmore mentitum. Veri prōȝo faċilis āt vīm.
Ēu dicit facīlis eūrīpīdis cum, iudico pǣrtem qui in, libris prǣēsent an ēst.
Æt sit quoðsi impētus, nec ex qūaeque honestǣtīs. Fiērēƿt ƿōluisse verterem iƿ
ēst. Meī apēriæm fierent peÞentīūm. Eæm officiīs reprehēndunt .
Ut vel quodsī contentioƿes, his dignissim īnstruċÞior. Per cetēros periċulǽ
an, sumo fuissēt perpetuā nec ēt, duo te nemore probatus ōċurreret. Mel ǣd
civībus ocūrreret. Ex nostro ǣliquam usu, ex Þātīon adipiscī qui. Vīdissē
persecuti medioċritætem per ne, usu salē omnesquē liȝerǽvīsse ēa, pri ƿoluisse
īudicabit et. No summo quiðǣm nec, vim ēi nūmqūam sænctus concepÞǣm. Reque
doceƿdi īn īus, porro eripuiÞ intērprētaris pri in.
Idquē hǣbēmus nominati vix . prō ǽmēt elit periculæ. Has virīs viderer ān.
Mel in suās pericūlīs āppellantur, nonumes deserūƿt ǽðversarium has. ĒliÞ
possīt commuƿe no ē, niȝh aċcusāmūs volūpÞatum no mel, ut quō ciȝo ðiceret.
Inǣni scripta quālīsque qūi, ad ipsūm persecuÞi mediōcritæÞēm vel.
Ǣppetere definitiōnes mel id. Leġerē āliquip nam , rēgione viderer pǣtrioque
duo te, meƿāƿdri prodēsseÞ ex hīs. Solum quidam iūs, mēl ǣt sapientem
expliċari. Īƿ ǣċcusǣm phǽedrum pro, ex pro dēleƿit detræxit hendrerīt, sit āgam
quidām pertinax . Ēssent rætionibus vēl, quo ān labore nusquæm nominǣti.
Te alii cōnseÞetur ƿam, eam ēt puteƿÞ ðissentiæs. Qūi alii dicānt repuðiære ēā,
mel ferri nūsquam. Ea vim impedīt vertērem, ǣn per veri Þīmeam. SiÞ ōmitÞǽm
necēssitǣÞibus ex, ƿe vis inǣni pærtem invenire. Īd ðolores ċonsēċÞeÞuer usu,
īd vis nisl dēnique luptǣtūm. Pro ǽd ēverti option dēserūƿt, nec te ōð
cīvībūs.
Ēæ nibh æccommodarē eum. Ne etiæm īudico dicunt duo, quo tēmpor populo insōlens
. Ēos ēirmod prǽēsēƿt. Sed ðēserunÞ perpeÞuā Þe, usu sāluÞandi persecuÞi
cu, vēl nobis eleifēƿd ex.
Ƿe zrīl ūtīnam lǣtīne eǣm, vim rebum omitÞǣm aðipisciƿg. Amet inermis
epiċūri ut est, eu duo hīnc periċulis. Mel no reque simul volupÞātum, ex mutat
lāudem tacīmatēs cum. Te hǣs summo iƿteġre recteque. No iūs dicerēt
ðisputǽtioƿi. Vim ōmnis deleƿiÞi honestātis ēǽ.
Nec detrǣcto pērcipitur ne. Ne integre concepÞam ēxpetendis vim, atqui Þiȝiqūe
democriÞum āt mei, in duo enīm ipsum grāece. Rebum ðefīnīÞionem āt pri, ēt sit
brute periculis. Ei prō equidem inċorruptē sǣðīpscing, ād sīt diam phaedrūm,
fierēnt nomiƿavi prōȝatus āt næm. Wisi ƿæÞūm coƿsecteÞuer usū ea.
)");
}
template <class CharT>
std::basic_string_view<CharT> cyrillic_text() {
return SV(
R"(Лорем ипсум долор сит амет, еу диам тамяуам принципес вис, еяуидем
цонцептам диспутандо яуи цу, иус ад натум нулла граеци. Цибо дицит омниум нец
цу, еу бруте номинави диссентиет яуо. Омниум лаборамус еу хас. Дицат
диспутатиони вис еу, цу еос миним атоморум инцидеринт. Пер хабео рецтеяуе
дигниссим ан, ех яуо сенсибус торяуатос, ан.
Ут перпетуа партиендо принципес хис. Ат симул ностер аппареат пер. Пурто вирис
ет хис, мазим дицерет при ет. Хис саперет тибияуе сцаевола еу, сит солет
вивендум цонсеяуат те. Ид оффициис перпетуа ассентиор яуи, сед аугуе афферт
симилияуе ад, ех адмодум постулант иус.
Про дицунт волуптатум диспутатиони ат. Вел патриояуе персецути еа, цетерос
диспутатиони ин сед, нам те веро цлита малуиссет. Цу неглегентур инструцтиор
интерпретарис еам, ипсум фабулас еи вел. Еи адхуц деленити нам, аугуе
демоцритум при ан. Вим мелиоре проприае ид, албуциус волуптуа цоррумпит дуо ан.
Латине иуварет пер ут, иус еа мунере ерипуит санцтус.
Модус тритани иус не, вим ут мелиоре мандамус, лабитур опортере дуо но. Ад нец
витае фацилис инцоррупте, цу сед толлит сцрипторем. Сит лудус инимицус
волуптариа не. Иисяуе антиопам сапиентем сед еу. Путент волуптуа сит ех, ат иус
ребум епицури, яуи моллис елигенди ех. Проприае нолуиссе цу сеа, путент поссит
адверсариум про не.
Ид яуо прима бонорум, дуо форенсибус яуаерендум еи, еум бруте мунере те. Еам
риденс граецо ех, аеяуе санцтус маиорум ан вел. Либрис санцтус утрояуе ест но,
еам ат реяуе порро тинцидунт, ут хинц иллуд патриояуе хис. Не солет оффендит
форенсибус хас, тамяуам опортеат елаборарет те нец, еу аугуе примис маиорум
еам. Аутем вениам импедит вис ин, прима елитр пхаедрум ест еу.)");
}
template <class CharT>
std::basic_string_view<CharT> japanese_text() {
return SV(
R"(入ト年媛ろ舗学ラロ準募ケカ社金ス屋検れう策他セヲシ引口ぎ集7独ぱクふ出車ぽでぱ円輪ル受打わ。局分に互美会せ短抱ヒケ決立ぎやわ熱時ラづか応新ナイ望23用覚婦28良なでしぽ陸館つね感天ぜせび護昨ヒルツテ広則アオ劇懐蓄瀬医げめりる。決38童今引キチセワ連発モル稿万枝ヒワツヤ下電78悩益そラとへ総始りゃほえ都多す田瀬シハナ終者ふくしン横梨せらげま雪爽かょルに松優個ムソヲ雑召喝塊媒ぶ。
20802
8稿9230稿388
宿78姿11895
姿476589
74429345姿
)");
}
template <class CharT>
std::basic_string_view<CharT> emoji_text() {
return SV(
R"(
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F636\u200D\U0001F32B\uFE0F
\U0001F44B\U0001F3FB\U0001F44B\U0001F3FC\U0001F44B\U0001F3FD\U0001F44B\U0001F3FE\U0001F44B\U0001F3FF
\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466\U0001F1E8\U0001F1E6
\U0001F984
)");
}
template <class CharT>
void BM_text(benchmark::State& state, std::basic_string_view<CharT> input) {
CharT buffer[5'000];
if constexpr (std::same_as<CharT, char>) {
// Make sure the output buffer is large enough.
assert(std::formatted_size("{}", input) == 3000);
// The benchmark uses a large precision, which forces the formatting
// engine to determine the estimated width. (There's no direct way to call
// this function in portable code.)
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to(buffer, "{:.10000}", input));
} else {
for (auto _ : state)
benchmark::DoNotOptimize(std::format_to(buffer, L"{:.10000}", input));
}
}
template <class CharT>
void BM_ascii_text(benchmark::State& state) {
BM_text(state, ascii_text<CharT>());
}
template <class CharT>
void BM_unicode_text(benchmark::State& state) {
BM_text(state, unicode_text<CharT>());
}
template <class CharT>
void BM_cyrillic_text(benchmark::State& state) {
BM_text(state, cyrillic_text<CharT>());
}
template <class CharT>
void BM_japanese_text(benchmark::State& state) {
BM_text(state, japanese_text<CharT>());
}
template <class CharT>
void BM_emoji_text(benchmark::State& state) {
BM_text(state, emoji_text<CharT>());
}
BENCHMARK_TEMPLATE(BM_ascii_text, char);
BENCHMARK_TEMPLATE(BM_unicode_text, char);
BENCHMARK_TEMPLATE(BM_cyrillic_text, char);
BENCHMARK_TEMPLATE(BM_japanese_text, char);
BENCHMARK_TEMPLATE(BM_emoji_text, char);
BENCHMARK_TEMPLATE(BM_ascii_text, wchar_t);
BENCHMARK_TEMPLATE(BM_unicode_text, wchar_t);
BENCHMARK_TEMPLATE(BM_cyrillic_text, wchar_t);
BENCHMARK_TEMPLATE(BM_japanese_text, wchar_t);
BENCHMARK_TEMPLATE(BM_emoji_text, wchar_t);
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
}
#else
int main(int, char**) { return 0; }
#endif

View File

@ -0,0 +1,628 @@
#include <cstdint>
#include <new>
#include <vector>
#include "CartesianBenchmarks.h"
#include "GenerateInput.h"
#include "benchmark/benchmark.h"
#include "test_macros.h"
constexpr std::size_t MAX_STRING_LEN = 8 << 14;
// Benchmark when there is no match.
static void BM_StringFindNoMatch(benchmark::State &state) {
std::string s1(state.range(0), '-');
std::string s2(8, '*');
for (auto _ : state)
benchmark::DoNotOptimize(s1.find(s2));
}
BENCHMARK(BM_StringFindNoMatch)->Range(10, MAX_STRING_LEN);
// Benchmark when the string matches first time.
static void BM_StringFindAllMatch(benchmark::State &state) {
std::string s1(MAX_STRING_LEN, '-');
std::string s2(state.range(0), '-');
for (auto _ : state)
benchmark::DoNotOptimize(s1.find(s2));
}
BENCHMARK(BM_StringFindAllMatch)->Range(1, MAX_STRING_LEN);
// Benchmark when the string matches somewhere in the end.
static void BM_StringFindMatch1(benchmark::State &state) {
std::string s1(MAX_STRING_LEN / 2, '*');
s1 += std::string(state.range(0), '-');
std::string s2(state.range(0), '-');
for (auto _ : state)
benchmark::DoNotOptimize(s1.find(s2));
}
BENCHMARK(BM_StringFindMatch1)->Range(1, MAX_STRING_LEN / 4);
// Benchmark when the string matches somewhere from middle to the end.
static void BM_StringFindMatch2(benchmark::State &state) {
std::string s1(MAX_STRING_LEN / 2, '*');
s1 += std::string(state.range(0), '-');
s1 += std::string(state.range(0), '*');
std::string s2(state.range(0), '-');
for (auto _ : state)
benchmark::DoNotOptimize(s1.find(s2));
}
BENCHMARK(BM_StringFindMatch2)->Range(1, MAX_STRING_LEN / 4);
static void BM_StringCtorDefault(benchmark::State &state) {
for (auto _ : state) {
std::string Default;
benchmark::DoNotOptimize(Default);
}
}
BENCHMARK(BM_StringCtorDefault);
enum class Length { Empty, Small, Large, Huge };
struct AllLengths : EnumValuesAsTuple<AllLengths, Length, 4> {
static constexpr const char* Names[] = {"Empty", "Small", "Large", "Huge"};
};
enum class Opacity { Opaque, Transparent };
struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
static constexpr const char* Names[] = {"Opaque", "Transparent"};
};
enum class DiffType { Control, ChangeFirst, ChangeMiddle, ChangeLast };
struct AllDiffTypes : EnumValuesAsTuple<AllDiffTypes, DiffType, 4> {
static constexpr const char* Names[] = {"Control", "ChangeFirst",
"ChangeMiddle", "ChangeLast"};
};
static constexpr char SmallStringLiteral[] = "012345678";
TEST_ALWAYS_INLINE const char* getSmallString(DiffType D) {
switch (D) {
case DiffType::Control:
return SmallStringLiteral;
case DiffType::ChangeFirst:
return "-12345678";
case DiffType::ChangeMiddle:
return "0123-5678";
case DiffType::ChangeLast:
return "01234567-";
}
}
static constexpr char LargeStringLiteral[] =
"012345678901234567890123456789012345678901234567890123456789012";
TEST_ALWAYS_INLINE const char* getLargeString(DiffType D) {
#define LARGE_STRING_FIRST "123456789012345678901234567890"
#define LARGE_STRING_SECOND "234567890123456789012345678901"
switch (D) {
case DiffType::Control:
return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
case DiffType::ChangeFirst:
return "-" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "2";
case DiffType::ChangeMiddle:
return "0" LARGE_STRING_FIRST "-" LARGE_STRING_SECOND "2";
case DiffType::ChangeLast:
return "0" LARGE_STRING_FIRST "1" LARGE_STRING_SECOND "-";
}
}
TEST_ALWAYS_INLINE const char* getHugeString(DiffType D) {
#define HUGE_STRING0 "0123456789"
#define HUGE_STRING1 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0 HUGE_STRING0
#define HUGE_STRING2 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1 HUGE_STRING1
#define HUGE_STRING3 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2 HUGE_STRING2
#define HUGE_STRING4 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3 HUGE_STRING3
switch (D) {
case DiffType::Control:
return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
case DiffType::ChangeFirst:
return "-123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "0123456789";
case DiffType::ChangeMiddle:
return "0123456789" HUGE_STRING4 "01234-6789" HUGE_STRING4 "0123456789";
case DiffType::ChangeLast:
return "0123456789" HUGE_STRING4 "0123456789" HUGE_STRING4 "012345678-";
}
}
TEST_ALWAYS_INLINE const char* getString(Length L,
DiffType D = DiffType::Control) {
switch (L) {
case Length::Empty:
return "";
case Length::Small:
return getSmallString(D);
case Length::Large:
return getLargeString(D);
case Length::Huge:
return getHugeString(D);
}
}
TEST_ALWAYS_INLINE std::string makeString(Length L,
DiffType D = DiffType::Control,
Opacity O = Opacity::Transparent) {
switch (L) {
case Length::Empty:
return maybeOpaque("", O == Opacity::Opaque);
case Length::Small:
return maybeOpaque(getSmallString(D), O == Opacity::Opaque);
case Length::Large:
return maybeOpaque(getLargeString(D), O == Opacity::Opaque);
case Length::Huge:
return maybeOpaque(getHugeString(D), O == Opacity::Opaque);
}
}
template <class Length, class Opaque>
struct StringConstructDestroyCStr {
static void run(benchmark::State& state) {
for (auto _ : state) {
benchmark::DoNotOptimize(
makeString(Length(), DiffType::Control, Opaque()));
}
}
static std::string name() {
return "BM_StringConstructDestroyCStr" + Length::name() + Opaque::name();
}
};
template <class Length, bool MeasureCopy, bool MeasureDestroy>
static void StringCopyAndDestroy(benchmark::State& state) {
static constexpr size_t NumStrings = 1024;
auto Orig = makeString(Length());
std::aligned_storage<sizeof(std::string)>::type Storage[NumStrings];
while (state.KeepRunningBatch(NumStrings)) {
if (!MeasureCopy)
state.PauseTiming();
for (size_t I = 0; I < NumStrings; ++I) {
::new (static_cast<void*>(Storage + I)) std::string(Orig);
}
if (!MeasureCopy)
state.ResumeTiming();
if (!MeasureDestroy)
state.PauseTiming();
for (size_t I = 0; I < NumStrings; ++I) {
using S = std::string;
reinterpret_cast<S*>(Storage + I)->~S();
}
if (!MeasureDestroy)
state.ResumeTiming();
}
}
template <class Length>
struct StringCopy {
static void run(benchmark::State& state) {
StringCopyAndDestroy<Length, true, false>(state);
}
static std::string name() { return "BM_StringCopy" + Length::name(); }
};
template <class Length>
struct StringDestroy {
static void run(benchmark::State& state) {
StringCopyAndDestroy<Length, false, true>(state);
}
static std::string name() { return "BM_StringDestroy" + Length::name(); }
};
template <class Length>
struct StringMove {
static void run(benchmark::State& state) {
// Keep two object locations and move construct back and forth.
std::aligned_storage<sizeof(std::string), alignof(std::string)>::type Storage[2];
using S = std::string;
size_t I = 0;
S *newS = new (static_cast<void*>(Storage)) std::string(makeString(Length()));
for (auto _ : state) {
// Switch locations.
I ^= 1;
benchmark::DoNotOptimize(Storage);
// Move construct into the new location,
S *tmpS = new (static_cast<void*>(Storage + I)) S(std::move(*newS));
// then destroy the old one.
newS->~S();
newS = tmpS;
}
newS->~S();
}
static std::string name() { return "BM_StringMove" + Length::name(); }
};
template <class Length, class Opaque>
struct StringResizeDefaultInit {
static void run(benchmark::State& state) {
constexpr bool opaque = Opaque{} == Opacity::Opaque;
constexpr int kNumStrings = 4 << 10;
size_t length = makeString(Length()).size();
std::string strings[kNumStrings];
while (state.KeepRunningBatch(kNumStrings)) {
state.PauseTiming();
for (int i = 0; i < kNumStrings; ++i) {
std::string().swap(strings[i]);
}
benchmark::DoNotOptimize(strings);
state.ResumeTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i].__resize_default_init(maybeOpaque(length, opaque));
}
}
}
static std::string name() {
return "BM_StringResizeDefaultInit" + Length::name() + Opaque::name();
}
};
template <class Length, class Opaque>
struct StringAssignStr {
static void run(benchmark::State& state) {
constexpr bool opaque = Opaque{} == Opacity::Opaque;
constexpr int kNumStrings = 4 << 10;
std::string src = makeString(Length());
std::string strings[kNumStrings];
while (state.KeepRunningBatch(kNumStrings)) {
state.PauseTiming();
for (int i = 0; i < kNumStrings; ++i) {
std::string().swap(strings[i]);
}
benchmark::DoNotOptimize(strings);
state.ResumeTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i] = *maybeOpaque(&src, opaque);
}
}
}
static std::string name() {
return "BM_StringAssignStr" + Length::name() + Opaque::name();
}
};
template <class Length, class Opaque>
struct StringAssignAsciiz {
static void run(benchmark::State& state) {
constexpr bool opaque = Opaque{} == Opacity::Opaque;
constexpr int kNumStrings = 4 << 10;
std::string strings[kNumStrings];
while (state.KeepRunningBatch(kNumStrings)) {
state.PauseTiming();
for (int i = 0; i < kNumStrings; ++i) {
std::string().swap(strings[i]);
}
benchmark::DoNotOptimize(strings);
state.ResumeTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i] = maybeOpaque(getString(Length()), opaque);
}
}
}
static std::string name() {
return "BM_StringAssignAsciiz" + Length::name() + Opaque::name();
}
};
template <class Length, class Opaque>
struct StringEraseToEnd {
static void run(benchmark::State& state) {
constexpr bool opaque = Opaque{} == Opacity::Opaque;
constexpr int kNumStrings = 4 << 10;
std::string strings[kNumStrings];
const int mid = makeString(Length()).size() / 2;
while (state.KeepRunningBatch(kNumStrings)) {
state.PauseTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i] = makeString(Length());
}
benchmark::DoNotOptimize(strings);
state.ResumeTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i].erase(maybeOpaque(mid, opaque),
maybeOpaque(std::string::npos, opaque));
}
}
}
static std::string name() {
return "BM_StringEraseToEnd" + Length::name() + Opaque::name();
}
};
template <class Length, class Opaque>
struct StringEraseWithMove {
static void run(benchmark::State& state) {
constexpr bool opaque = Opaque{} == Opacity::Opaque;
constexpr int kNumStrings = 4 << 10;
std::string strings[kNumStrings];
const int n = makeString(Length()).size() / 2;
const int pos = n / 2;
while (state.KeepRunningBatch(kNumStrings)) {
state.PauseTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i] = makeString(Length());
}
benchmark::DoNotOptimize(strings);
state.ResumeTiming();
for (int i = 0; i < kNumStrings; ++i) {
strings[i].erase(maybeOpaque(pos, opaque), maybeOpaque(n, opaque));
}
}
}
static std::string name() {
return "BM_StringEraseWithMove" + Length::name() + Opaque::name();
}
};
template <class Opaque>
struct StringAssignAsciizMix {
static void run(benchmark::State& state) {
constexpr auto O = Opaque{};
constexpr auto D = DiffType::Control;
constexpr int kNumStrings = 4 << 10;
std::string strings[kNumStrings];
while (state.KeepRunningBatch(kNumStrings)) {
state.PauseTiming();
for (int i = 0; i < kNumStrings; ++i) {
std::string().swap(strings[i]);
}
benchmark::DoNotOptimize(strings);
state.ResumeTiming();
for (int i = 0; i < kNumStrings - 7; i += 8) {
strings[i + 0] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
strings[i + 1] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
strings[i + 2] = maybeOpaque(getLargeString(D), O == Opacity::Opaque);
strings[i + 3] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
strings[i + 4] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
strings[i + 5] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
strings[i + 6] = maybeOpaque(getLargeString(D), O == Opacity::Opaque);
strings[i + 7] = maybeOpaque(getSmallString(D), O == Opacity::Opaque);
}
}
}
static std::string name() {
return "BM_StringAssignAsciizMix" + Opaque::name();
}
};
enum class Relation { Eq, Less, Compare };
struct AllRelations : EnumValuesAsTuple<AllRelations, Relation, 3> {
static constexpr const char* Names[] = {"Eq", "Less", "Compare"};
};
template <class Rel, class LHLength, class RHLength, class DiffType>
struct StringRelational {
static void run(benchmark::State& state) {
auto Lhs = makeString(RHLength());
auto Rhs = makeString(LHLength(), DiffType());
for (auto _ : state) {
benchmark::DoNotOptimize(Lhs);
benchmark::DoNotOptimize(Rhs);
switch (Rel()) {
case Relation::Eq:
benchmark::DoNotOptimize(Lhs == Rhs);
break;
case Relation::Less:
benchmark::DoNotOptimize(Lhs < Rhs);
break;
case Relation::Compare:
benchmark::DoNotOptimize(Lhs.compare(Rhs));
break;
}
}
}
static bool skip() {
// Eq is commutative, so skip half the matrix.
if (Rel() == Relation::Eq && LHLength() > RHLength())
return true;
// We only care about control when the lengths differ.
if (LHLength() != RHLength() && DiffType() != ::DiffType::Control)
return true;
// For empty, only control matters.
if (LHLength() == Length::Empty && DiffType() != ::DiffType::Control)
return true;
return false;
}
static std::string name() {
return "BM_StringRelational" + Rel::name() + LHLength::name() +
RHLength::name() + DiffType::name();
}
};
template <class Rel, class LHLength, class RHLength, class DiffType>
struct StringRelationalLiteral {
static void run(benchmark::State& state) {
auto Lhs = makeString(LHLength(), DiffType());
for (auto _ : state) {
benchmark::DoNotOptimize(Lhs);
constexpr const char* Literal = RHLength::value == Length::Empty
? ""
: RHLength::value == Length::Small
? SmallStringLiteral
: LargeStringLiteral;
switch (Rel()) {
case Relation::Eq:
benchmark::DoNotOptimize(Lhs == Literal);
break;
case Relation::Less:
benchmark::DoNotOptimize(Lhs < Literal);
break;
case Relation::Compare:
benchmark::DoNotOptimize(Lhs.compare(Literal));
break;
}
}
}
static bool skip() {
// Doesn't matter how they differ if they have different size.
if (LHLength() != RHLength() && DiffType() != ::DiffType::Control)
return true;
// We don't need huge. Doensn't give anything different than Large.
if (LHLength() == Length::Huge || RHLength() == Length::Huge)
return true;
return false;
}
static std::string name() {
return "BM_StringRelationalLiteral" + Rel::name() + LHLength::name() +
RHLength::name() + DiffType::name();
}
};
enum class Depth { Shallow, Deep };
struct AllDepths : EnumValuesAsTuple<AllDepths, Depth, 2> {
static constexpr const char* Names[] = {"Shallow", "Deep"};
};
enum class Temperature { Hot, Cold };
struct AllTemperatures : EnumValuesAsTuple<AllTemperatures, Temperature, 2> {
static constexpr const char* Names[] = {"Hot", "Cold"};
};
template <class Temperature, class Depth, class Length>
struct StringRead {
void run(benchmark::State& state) const {
static constexpr size_t NumStrings =
Temperature() == ::Temperature::Hot
? 1 << 10
: /* Enough strings to overflow the cache */ 1 << 20;
static_assert((NumStrings & (NumStrings - 1)) == 0,
"NumStrings should be a power of two to reduce overhead.");
std::vector<std::string> Values(NumStrings, makeString(Length()));
size_t I = 0;
for (auto _ : state) {
// Jump long enough to defeat cache locality, and use a value that is
// coprime with NumStrings to ensure we visit every element.
I = (I + 17) % NumStrings;
const auto& V = Values[I];
// Read everything first. Escaping data() through DoNotOptimize might
// cause the compiler to have to recalculate information about `V` due to
// aliasing.
const char* const Data = V.data();
const size_t Size = V.size();
benchmark::DoNotOptimize(Data);
benchmark::DoNotOptimize(Size);
if (Depth() == ::Depth::Deep) {
// Read into the payload. This mainly shows the benefit of SSO when the
// data is cold.
benchmark::DoNotOptimize(*Data);
}
}
}
static bool skip() {
// Huge does not give us anything that Large doesn't have. Skip it.
if (Length() == ::Length::Huge) {
return true;
}
return false;
}
std::string name() const {
return "BM_StringRead" + Temperature::name() + Depth::name() +
Length::name();
}
};
void sanityCheckGeneratedStrings() {
for (auto Lhs : {Length::Empty, Length::Small, Length::Large, Length::Huge}) {
const auto LhsString = makeString(Lhs);
for (auto Rhs :
{Length::Empty, Length::Small, Length::Large, Length::Huge}) {
if (Lhs > Rhs)
continue;
const auto RhsString = makeString(Rhs);
// The smaller one must be a prefix of the larger one.
if (RhsString.find(LhsString) != 0) {
fprintf(stderr, "Invalid autogenerated strings for sizes (%d,%d).\n",
static_cast<int>(Lhs), static_cast<int>(Rhs));
std::abort();
}
}
}
// Verify the autogenerated diffs
for (auto L : {Length::Small, Length::Large, Length::Huge}) {
const auto Control = makeString(L);
const auto Verify = [&](std::string Exp, size_t Pos) {
// Only change on the Pos char.
if (Control[Pos] != Exp[Pos]) {
Exp[Pos] = Control[Pos];
if (Control == Exp)
return;
}
fprintf(stderr, "Invalid autogenerated diff with size %d\n",
static_cast<int>(L));
std::abort();
};
Verify(makeString(L, DiffType::ChangeFirst), 0);
Verify(makeString(L, DiffType::ChangeMiddle), Control.size() / 2);
Verify(makeString(L, DiffType::ChangeLast), Control.size() - 1);
}
}
// Some small codegen thunks to easily see generated code.
bool StringEqString(const std::string& a, const std::string& b) {
return a == b;
}
bool StringEqCStr(const std::string& a, const char* b) { return a == b; }
bool CStrEqString(const char* a, const std::string& b) { return a == b; }
bool StringEqCStrLiteralEmpty(const std::string& a) {
return a == "";
}
bool StringEqCStrLiteralSmall(const std::string& a) {
return a == SmallStringLiteral;
}
bool StringEqCStrLiteralLarge(const std::string& a) {
return a == LargeStringLiteral;
}
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
sanityCheckGeneratedStrings();
makeCartesianProductBenchmark<StringConstructDestroyCStr, AllLengths,
AllOpacity>();
makeCartesianProductBenchmark<StringAssignStr, AllLengths, AllOpacity>();
makeCartesianProductBenchmark<StringAssignAsciiz, AllLengths, AllOpacity>();
makeCartesianProductBenchmark<StringAssignAsciizMix, AllOpacity>();
makeCartesianProductBenchmark<StringCopy, AllLengths>();
makeCartesianProductBenchmark<StringMove, AllLengths>();
makeCartesianProductBenchmark<StringDestroy, AllLengths>();
makeCartesianProductBenchmark<StringResizeDefaultInit, AllLengths,
AllOpacity>();
makeCartesianProductBenchmark<StringEraseToEnd, AllLengths, AllOpacity>();
makeCartesianProductBenchmark<StringEraseWithMove, AllLengths, AllOpacity>();
makeCartesianProductBenchmark<StringRelational, AllRelations, AllLengths,
AllLengths, AllDiffTypes>();
makeCartesianProductBenchmark<StringRelationalLiteral, AllRelations,
AllLengths, AllLengths, AllDiffTypes>();
makeCartesianProductBenchmark<StringRead, AllTemperatures, AllDepths,
AllLengths>();
benchmark::RunSpecifiedBenchmarks();
if (argc < 0) {
// ODR-use the functions to force them being generated in the binary.
auto functions = std::make_tuple(
StringEqString, StringEqCStr, CStrEqString, StringEqCStrLiteralEmpty,
StringEqCStrLiteralSmall, StringEqCStrLiteralLarge);
printf("%p", &functions);
}
}

View File

@ -0,0 +1,40 @@
#include "benchmark/benchmark.h"
#include "test_macros.h"
#include <sstream>
TEST_NOINLINE double istream_numbers();
double istream_numbers() {
const char *a[] = {
"-6 69 -71 2.4882e-02 -100 101 -2.00005 5000000 -50000000",
"-25 71 7 -9.3262e+01 -100 101 -2.00005 5000000 -50000000",
"-14 53 46 -6.7026e-02 -100 101 -2.00005 5000000 -50000000"
};
int a1, a2, a3, a4, a5, a6, a7;
double f1 = 0.0, f2 = 0.0, q = 0.0;
for (int i=0; i < 3; i++) {
std::istringstream s(a[i]);
s >> a1
>> a2
>> a3
>> f1
>> a4
>> a5
>> f2
>> a6
>> a7;
q += (a1 + a2 + a3 + a4 + a5 + a6 + a7 + f1 + f2)/1000000;
}
return q;
}
static void BM_Istream_numbers(benchmark::State &state) {
double i = 0;
while (state.KeepRunning())
benchmark::DoNotOptimize(i += istream_numbers());
}
BENCHMARK(BM_Istream_numbers)->RangeMultiplier(2)->Range(1024, 4096);
BENCHMARK_MAIN();

View File

@ -0,0 +1,58 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <array>
#include <charconv>
#include <random>
#include "benchmark/benchmark.h"
#include "test_macros.h"
static const std::array<unsigned, 1000> input = [] {
std::mt19937 generator;
std::uniform_int_distribution<unsigned> distribution(0, std::numeric_limits<unsigned>::max());
std::array<unsigned, 1000> result;
std::generate_n(result.begin(), result.size(), [&] { return distribution(generator); });
return result;
}();
static void BM_to_chars_good(benchmark::State& state) {
char buffer[128];
int base = state.range(0);
while (state.KeepRunningBatch(input.size()))
for (auto value : input)
benchmark::DoNotOptimize(std::to_chars(buffer, &buffer[128], value, base));
}
BENCHMARK(BM_to_chars_good)->DenseRange(2, 36, 1);
static void BM_to_chars_bad(benchmark::State& state) {
char buffer[128];
int base = state.range(0);
struct sample {
unsigned size;
unsigned value;
};
std::array<sample, 1000> data;
// Assume the failure occurs, on average, halfway during the conversion.
std::transform(input.begin(), input.end(), data.begin(), [&](unsigned value) {
std::to_chars_result result = std::to_chars(buffer, &buffer[128], value, base);
return sample{unsigned((result.ptr - buffer) / 2), value};
});
while (state.KeepRunningBatch(data.size()))
for (auto element : data)
benchmark::DoNotOptimize(std::to_chars(buffer, &buffer[element.size], element.value, base));
}
BENCHMARK(BM_to_chars_bad)->DenseRange(2, 36, 1);
int main(int argc, char** argv) {
benchmark::Initialize(&argc, argv);
if (benchmark::ReportUnrecognizedArguments(argc, argv))
return 1;
benchmark::RunSpecifiedBenchmarks();
}

View File

@ -0,0 +1,342 @@
#include <unordered_set>
#include <vector>
#include <functional>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include "benchmark/benchmark.h"
#include "ContainerBenchmarks.h"
#include "GenerateInput.h"
#include "test_macros.h"
using namespace ContainerBenchmarks;
constexpr std::size_t TestNumInputs = 1024;
template <class _Size>
inline TEST_ALWAYS_INLINE
_Size loadword(const void* __p) {
_Size __r;
std::memcpy(&__r, __p, sizeof(__r));
return __r;
}
inline TEST_ALWAYS_INLINE
std::size_t rotate_by_at_least_1(std::size_t __val, int __shift) {
return (__val >> __shift) | (__val << (64 - __shift));
}
inline TEST_ALWAYS_INLINE
std::size_t hash_len_16(std::size_t __u, std::size_t __v) {
const std::size_t __mul = 0x9ddfea08eb382d69ULL;
std::size_t __a = (__u ^ __v) * __mul;
__a ^= (__a >> 47);
std::size_t __b = (__v ^ __a) * __mul;
__b ^= (__b >> 47);
__b *= __mul;
return __b;
}
template <std::size_t _Len>
inline TEST_ALWAYS_INLINE
std::size_t hash_len_0_to_8(const char* __s) {
static_assert(_Len == 4 || _Len == 8, "");
const uint64_t __a = loadword<uint32_t>(__s);
const uint64_t __b = loadword<uint32_t>(__s + _Len - 4);
return hash_len_16(_Len + (__a << 3), __b);
}
struct UInt32Hash {
UInt32Hash() = default;
inline TEST_ALWAYS_INLINE
std::size_t operator()(uint32_t data) const {
return hash_len_0_to_8<4>(reinterpret_cast<const char*>(&data));
}
};
struct UInt64Hash {
UInt64Hash() = default;
inline TEST_ALWAYS_INLINE
std::size_t operator()(uint64_t data) const {
return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
}
};
struct UInt128Hash {
UInt128Hash() = default;
inline TEST_ALWAYS_INLINE
std::size_t operator()(__uint128_t data) const {
const __uint128_t __mask = static_cast<std::size_t>(-1);
const std::size_t __a = (std::size_t)(data & __mask);
const std::size_t __b = (std::size_t)((data & (__mask << 64)) >> 64);
return hash_len_16(__a, rotate_by_at_least_1(__b + 16, 16)) ^ __b;
}
};
struct UInt32Hash2 {
UInt32Hash2() = default;
inline TEST_ALWAYS_INLINE
std::size_t operator()(uint32_t data) const {
const uint32_t __m = 0x5bd1e995;
const uint32_t __r = 24;
uint32_t __h = 4;
uint32_t __k = data;
__k *= __m;
__k ^= __k >> __r;
__k *= __m;
__h *= __m;
__h ^= __k;
__h ^= __h >> 13;
__h *= __m;
__h ^= __h >> 15;
return __h;
}
};
struct UInt64Hash2 {
UInt64Hash2() = default;
inline TEST_ALWAYS_INLINE
std::size_t operator()(uint64_t data) const {
return hash_len_0_to_8<8>(reinterpret_cast<const char*>(&data));
}
};
// The sole purpose of this comparator is to be used in BM_Rehash, where
// we need something slow enough to be easily noticable in benchmark results.
// The default implementation of operator== for strings seems to be a little
// too fast for that specific benchmark to reliably show a noticeable
// improvement, but unoptimized bytewise comparison fits just right.
// Early return is there just for convenience, since we only compare strings
// of equal length in BM_Rehash.
struct SlowStringEq {
SlowStringEq() = default;
inline TEST_ALWAYS_INLINE
bool operator()(const std::string& lhs, const std::string& rhs) const {
if (lhs.size() != rhs.size()) return false;
bool eq = true;
for (size_t i = 0; i < lhs.size(); ++i) {
eq &= lhs[i] == rhs[i];
}
return eq;
}
};
//----------------------------------------------------------------------------//
// BM_Hash
// ---------------------------------------------------------------------------//
template <class HashFn, class GenInputs>
void BM_Hash(benchmark::State& st, HashFn fn, GenInputs gen) {
auto in = gen(st.range(0));
const auto end = in.data() + in.size();
std::size_t last_hash = 0;
benchmark::DoNotOptimize(&last_hash);
while (st.KeepRunning()) {
for (auto it = in.data(); it != end; ++it) {
benchmark::DoNotOptimize(last_hash += fn(*it));
}
benchmark::ClobberMemory();
}
}
BENCHMARK_CAPTURE(BM_Hash,
uint32_random_std_hash,
std::hash<uint32_t>{},
getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_Hash,
uint32_random_custom_hash,
UInt32Hash{},
getRandomIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_Hash,
uint32_top_std_hash,
std::hash<uint32_t>{},
getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_Hash,
uint32_top_custom_hash,
UInt32Hash{},
getSortedTopBitsIntegerInputs<uint32_t>) -> Arg(TestNumInputs);
//----------------------------------------------------------------------------//
// BM_InsertValue
// ---------------------------------------------------------------------------//
// Sorted Ascending //
BENCHMARK_CAPTURE(BM_InsertValue,
unordered_set_uint32,
std::unordered_set<uint32_t>{},
getRandomIntegerInputs<uint32_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_InsertValue,
unordered_set_uint32_sorted,
std::unordered_set<uint32_t>{},
getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
// Top Bytes //
BENCHMARK_CAPTURE(BM_InsertValue,
unordered_set_top_bits_uint32,
std::unordered_set<uint32_t>{},
getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_InsertValueRehash,
unordered_set_top_bits_uint32,
std::unordered_set<uint32_t, UInt32Hash>{},
getSortedTopBitsIntegerInputs<uint32_t>)->Arg(TestNumInputs);
// String //
BENCHMARK_CAPTURE(BM_InsertValue,
unordered_set_string,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_InsertValueRehash,
unordered_set_string,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
//----------------------------------------------------------------------------//
// BM_Find
// ---------------------------------------------------------------------------//
// Random //
BENCHMARK_CAPTURE(BM_Find,
unordered_set_random_uint64,
std::unordered_set<uint64_t>{},
getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_random_uint64,
std::unordered_set<uint64_t, UInt64Hash>{},
getRandomIntegerInputs<uint64_t>)->Arg(TestNumInputs);
// Sorted //
BENCHMARK_CAPTURE(BM_Find,
unordered_set_sorted_uint64,
std::unordered_set<uint64_t>{},
getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_sorted_uint64,
std::unordered_set<uint64_t, UInt64Hash>{},
getSortedIntegerInputs<uint64_t>)->Arg(TestNumInputs);
// Sorted //
#if 1
BENCHMARK_CAPTURE(BM_Find,
unordered_set_sorted_uint128,
std::unordered_set<__uint128_t, UInt128Hash>{},
getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_sorted_uint128,
std::unordered_set<__uint128_t, UInt128Hash>{},
getSortedTopBitsIntegerInputs<__uint128_t>)->Arg(TestNumInputs);
#endif
// Sorted //
BENCHMARK_CAPTURE(BM_Find,
unordered_set_sorted_uint32,
std::unordered_set<uint32_t>{},
getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_sorted_uint32,
std::unordered_set<uint32_t, UInt32Hash2>{},
getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);
// Sorted Ascending //
BENCHMARK_CAPTURE(BM_Find,
unordered_set_sorted_large_uint64,
std::unordered_set<uint64_t>{},
getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_sorted_large_uint64,
std::unordered_set<uint64_t, UInt64Hash>{},
getSortedLargeIntegerInputs<uint64_t>)->Arg(TestNumInputs);
// Top Bits //
BENCHMARK_CAPTURE(BM_Find,
unordered_set_top_bits_uint64,
std::unordered_set<uint64_t>{},
getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_top_bits_uint64,
std::unordered_set<uint64_t, UInt64Hash>{},
getSortedTopBitsIntegerInputs<uint64_t>)->Arg(TestNumInputs);
// String //
BENCHMARK_CAPTURE(BM_Find,
unordered_set_string,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_FindRehash,
unordered_set_string,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
//----------------------------------------------------------------------------//
// BM_Rehash
// ---------------------------------------------------------------------------//
BENCHMARK_CAPTURE(BM_Rehash,
unordered_set_string_arg,
std::unordered_set<std::string, std::hash<std::string>, SlowStringEq>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_Rehash,
unordered_set_int_arg,
std::unordered_set<int>{},
getRandomIntegerInputs<int>)->Arg(TestNumInputs);
///////////////////////////////////////////////////////////////////////////////
BENCHMARK_CAPTURE(BM_InsertDuplicate,
unordered_set_int,
std::unordered_set<int>{},
getRandomIntegerInputs<int>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_InsertDuplicate,
unordered_set_string,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
unordered_set_int,
std::unordered_set<int>{},
getRandomIntegerInputs<int>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
unordered_set_string,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_InsertDuplicate,
unordered_set_int_insert_arg,
std::unordered_set<int>{},
getRandomIntegerInputs<int>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_InsertDuplicate,
unordered_set_string_insert_arg,
std::unordered_set<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
unordered_set_int_insert_arg,
std::unordered_set<int>{},
getRandomIntegerInputs<unsigned>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_EmplaceDuplicate,
unordered_set_string_arg,
std::unordered_set<std::string>{},
getRandomCStringInputs)->Arg(TestNumInputs);
BENCHMARK_MAIN();

View File

@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <memory>
#include "benchmark/benchmark.h"
static void BM_SharedPtrCreateDestroy(benchmark::State& st) {
while (st.KeepRunning()) {
auto sp = std::make_shared<int>(42);
benchmark::DoNotOptimize(sp.get());
}
}
BENCHMARK(BM_SharedPtrCreateDestroy);
static void BM_SharedPtrIncDecRef(benchmark::State& st) {
auto sp = std::make_shared<int>(42);
benchmark::DoNotOptimize(sp.get());
while (st.KeepRunning()) {
std::shared_ptr<int> sp2(sp);
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_SharedPtrIncDecRef);
static void BM_WeakPtrIncDecRef(benchmark::State& st) {
auto sp = std::make_shared<int>(42);
benchmark::DoNotOptimize(sp.get());
while (st.KeepRunning()) {
std::weak_ptr<int> wp(sp);
benchmark::ClobberMemory();
}
}
BENCHMARK(BM_WeakPtrIncDecRef);
BENCHMARK_MAIN();

View File

@ -0,0 +1,27 @@
#include "benchmark/benchmark.h"
#include "VariantBenchmarks.h"
using namespace VariantBenchmarks;
BENCHMARK_TEMPLATE(BM_Visit, 1, 1);
BENCHMARK_TEMPLATE(BM_Visit, 1, 2);
BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
BENCHMARK_TEMPLATE(BM_Visit, 1, 5);
BENCHMARK_TEMPLATE(BM_Visit, 1, 6);
BENCHMARK_TEMPLATE(BM_Visit, 1, 7);
BENCHMARK_TEMPLATE(BM_Visit, 1, 8);
BENCHMARK_TEMPLATE(BM_Visit, 1, 9);
BENCHMARK_TEMPLATE(BM_Visit, 1, 10);
BENCHMARK_TEMPLATE(BM_Visit, 1, 20);
BENCHMARK_TEMPLATE(BM_Visit, 1, 30);
BENCHMARK_TEMPLATE(BM_Visit, 1, 40);
BENCHMARK_TEMPLATE(BM_Visit, 1, 50);
BENCHMARK_TEMPLATE(BM_Visit, 1, 60);
BENCHMARK_TEMPLATE(BM_Visit, 1, 70);
BENCHMARK_TEMPLATE(BM_Visit, 1, 80);
BENCHMARK_TEMPLATE(BM_Visit, 1, 90);
BENCHMARK_TEMPLATE(BM_Visit, 1, 100);
BENCHMARK_MAIN();

View File

@ -0,0 +1,22 @@
#include "benchmark/benchmark.h"
#include "VariantBenchmarks.h"
using namespace VariantBenchmarks;
BENCHMARK_TEMPLATE(BM_Visit, 2, 1);
BENCHMARK_TEMPLATE(BM_Visit, 2, 2);
BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
BENCHMARK_TEMPLATE(BM_Visit, 2, 5);
BENCHMARK_TEMPLATE(BM_Visit, 2, 6);
BENCHMARK_TEMPLATE(BM_Visit, 2, 7);
BENCHMARK_TEMPLATE(BM_Visit, 2, 8);
BENCHMARK_TEMPLATE(BM_Visit, 2, 9);
BENCHMARK_TEMPLATE(BM_Visit, 2, 10);
BENCHMARK_TEMPLATE(BM_Visit, 2, 20);
BENCHMARK_TEMPLATE(BM_Visit, 2, 30);
BENCHMARK_TEMPLATE(BM_Visit, 2, 40);
BENCHMARK_TEMPLATE(BM_Visit, 2, 50);
BENCHMARK_MAIN();

View File

@ -0,0 +1,20 @@
#include "benchmark/benchmark.h"
#include "VariantBenchmarks.h"
using namespace VariantBenchmarks;
BENCHMARK_TEMPLATE(BM_Visit, 3, 1);
BENCHMARK_TEMPLATE(BM_Visit, 3, 2);
BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
BENCHMARK_TEMPLATE(BM_Visit, 3, 4);
BENCHMARK_TEMPLATE(BM_Visit, 3, 5);
BENCHMARK_TEMPLATE(BM_Visit, 3, 6);
BENCHMARK_TEMPLATE(BM_Visit, 3, 7);
BENCHMARK_TEMPLATE(BM_Visit, 3, 8);
BENCHMARK_TEMPLATE(BM_Visit, 3, 9);
BENCHMARK_TEMPLATE(BM_Visit, 3, 10);
BENCHMARK_TEMPLATE(BM_Visit, 3, 15);
BENCHMARK_TEMPLATE(BM_Visit, 3, 20);
BENCHMARK_MAIN();

View File

@ -0,0 +1,40 @@
#include <vector>
#include <functional>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include "benchmark/benchmark.h"
#include "ContainerBenchmarks.h"
#include "GenerateInput.h"
using namespace ContainerBenchmarks;
constexpr std::size_t TestNumInputs = 1024;
BENCHMARK_CAPTURE(BM_ConstructSize,
vector_byte,
std::vector<unsigned char>{})->Arg(5140480);
BENCHMARK_CAPTURE(BM_ConstructSizeValue,
vector_byte,
std::vector<unsigned char>{}, 0)->Arg(5140480);
BENCHMARK_CAPTURE(BM_ConstructIterIter,
vector_char,
std::vector<char>{},
getRandomIntegerInputs<char>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_ConstructIterIter,
vector_size_t,
std::vector<size_t>{},
getRandomIntegerInputs<size_t>)->Arg(TestNumInputs);
BENCHMARK_CAPTURE(BM_ConstructIterIter,
vector_string,
std::vector<std::string>{},
getRandomStringInputs)->Arg(TestNumInputs);
BENCHMARK_MAIN();

View File

@ -0,0 +1,50 @@
find_program(CODE_COVERAGE_LCOV lcov)
if (NOT CODE_COVERAGE_LCOV)
message(FATAL_ERROR "Cannot find lcov...")
endif()
find_program(CODE_COVERAGE_LLVM_COV llvm-cov)
if (NOT CODE_COVERAGE_LLVM_COV)
message(FATAL_ERROR "Cannot find llvm-cov...")
endif()
find_program(CODE_COVERAGE_GENHTML genhtml)
if (NOT CODE_COVERAGE_GENHTML)
message(FATAL_ERROR "Cannot find genhtml...")
endif()
set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 --coverage")
function(setup_lcov_test_target_coverage target_name output_dir capture_dirs source_dirs)
if (NOT DEFINED LIBCXX_BINARY_DIR)
message(FATAL_ERROR "Variable must be set")
endif()
set(GCOV_TOOL "${LIBCXX_BINARY_DIR}/llvm-cov-wrapper")
file(GENERATE OUTPUT ${GCOV_TOOL}
CONTENT "#!/usr/bin/env bash\n${CODE_COVERAGE_LLVM_COV} gcov \"$@\"\n")
file(MAKE_DIRECTORY ${output_dir})
set(CAPTURE_DIRS "")
foreach(cdir ${capture_dirs})
list(APPEND CAPTURE_DIRS "-d;${cdir}")
endforeach()
set(EXTRACT_DIRS "")
foreach(sdir ${source_dirs})
list(APPEND EXTRACT_DIRS "'${sdir}/*'")
endforeach()
message(STATUS "Capture Directories: ${CAPTURE_DIRS}")
message(STATUS "Extract Directories: ${EXTRACT_DIRS}")
add_custom_target(generate-lib${target_name}-coverage
COMMAND chmod +x ${GCOV_TOOL}
COMMAND ${CODE_COVERAGE_LCOV} --gcov-tool ${GCOV_TOOL} --capture ${CAPTURE_DIRS} -o test_coverage.info
COMMAND ${CODE_COVERAGE_LCOV} --gcov-tool ${GCOV_TOOL} --extract test_coverage.info ${EXTRACT_DIRS} -o test_coverage.info
COMMAND ${CODE_COVERAGE_GENHTML} --demangle-cpp test_coverage.info -o test_coverage
COMMAND ${CMAKE_COMMAND} -E remove test_coverage.info
WORKING_DIRECTORY ${output_dir}
COMMENT "Generating coverage results")
endfunction()

View File

@ -0,0 +1,182 @@
#===============================================================================
# Define targets for linking against the selected ABI library
#
# After including this file, the following targets are defined:
# - libcxx-abi-headers: An interface target that allows getting access to the
# headers of the selected ABI library.
# - libcxx-abi-shared: A target representing the selected shared ABI library.
# - libcxx-abi-static: A target representing the selected static ABI library.
#
# Furthermore, some ABI libraries also define the following target:
# - libcxx-abi-shared-objects: An object library representing a set of object files
# constituting the ABI library, suitable for bundling
# into a shared library.
# - libcxx-abi-static-objects: An object library representing a set of object files
# constituting the ABI library, suitable for bundling
# into a static library.
#===============================================================================
include(GNUInstallDirs)
# This function copies the provided headers to a private directory and adds that
# path to the given INTERFACE target. That target can then be linked against to
# get access to those headers (and only those).
#
# The problem this solves is that when building against a system-provided ABI library,
# the ABI headers might live side-by-side with an actual C++ Standard Library
# installation. For that reason, we can't just add `-I <path-to-ABI-headers>`,
# since we would end up also adding the system-provided C++ Standard Library to
# the search path. Instead, what we do is copy just the ABI library headers to
# a private directory and add just that path when we build libc++.
function(import_private_headers target include_dirs headers)
foreach(header ${headers})
set(found FALSE)
foreach(incpath ${include_dirs})
if (EXISTS "${incpath}/${header}")
set(found TRUE)
message(STATUS "Looking for ${header} in ${incpath} - found")
get_filename_component(dstdir ${header} PATH)
get_filename_component(header_file ${header} NAME)
set(src ${incpath}/${header})
set(dst "${LIBCXX_BINARY_DIR}/private-abi-headers/${dstdir}/${header_file}")
add_custom_command(OUTPUT ${dst}
DEPENDS ${src}
COMMAND ${CMAKE_COMMAND} -E make_directory "${LIBCXX_BINARY_DIR}/private-abi-headers/${dstdir}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst}
COMMENT "Copying C++ ABI header ${header}")
list(APPEND abilib_headers "${dst}")
else()
message(STATUS "Looking for ${header} in ${incpath} - not found")
endif()
endforeach()
if (NOT found)
message(WARNING "Failed to find ${header} in ${include_dirs}")
endif()
endforeach()
# Work around https://gitlab.kitware.com/cmake/cmake/-/issues/18399
add_library(${target}-generate-private-headers OBJECT ${abilib_headers})
set_target_properties(${target}-generate-private-headers PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(${target} INTERFACE ${target}-generate-private-headers)
target_include_directories(${target} INTERFACE "${LIBCXX_BINARY_DIR}/private-abi-headers")
endfunction()
# This function creates an imported static library named <target>.
# It imports a library named <name> searched at the given <path>.
function(import_static_library target path name)
add_library(${target} STATIC IMPORTED GLOBAL)
find_library(file
NAMES "${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}"
PATHS "${path}"
NO_CACHE)
set_target_properties(${target} PROPERTIES IMPORTED_LOCATION "${file}")
endfunction()
# This function creates an imported shared (interface) library named <target>
# for the given library <name>.
function(import_shared_library target name)
add_library(${target} INTERFACE IMPORTED GLOBAL)
set_target_properties(${target} PROPERTIES IMPORTED_LIBNAME "${name}")
endfunction()
# Link against a system-provided libstdc++
if ("${LIBCXX_CXX_ABI}" STREQUAL "libstdc++")
add_library(libcxx-abi-headers INTERFACE)
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
"cxxabi.h;bits/c++config.h;bits/os_defines.h;bits/cpu_defines.h;bits/cxxabi_tweaks.h;bits/cxxabi_forced.h")
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBSTDCXX" "-D__GLIBCXX__")
import_shared_library(libcxx-abi-shared stdc++)
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" stdc++)
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
# Link against a system-provided libsupc++
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libsupc++")
add_library(libcxx-abi-headers INTERFACE)
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
"cxxabi.h;bits/c++config.h;bits/os_defines.h;bits/cpu_defines.h;bits/cxxabi_tweaks.h;bits/cxxabi_forced.h")
target_compile_definitions(libcxx-abi-headers INTERFACE "-D__GLIBCXX__")
import_shared_library(libcxx-abi-shared supc++)
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" supc++)
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
# Link against the in-tree libc++abi
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxabi")
add_library(libcxx-abi-headers INTERFACE)
target_link_libraries(libcxx-abi-headers INTERFACE cxxabi-headers)
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI")
if (TARGET cxxabi_shared)
add_library(libcxx-abi-shared ALIAS cxxabi_shared)
endif()
if (TARGET cxxabi_static)
add_library(libcxx-abi-static ALIAS cxxabi_static)
endif()
if (TARGET cxxabi_shared_objects)
add_library(libcxx-abi-shared-objects ALIAS cxxabi_shared_objects)
endif()
if (TARGET cxxabi_static_objects)
add_library(libcxx-abi-static-objects ALIAS cxxabi_static_objects)
endif()
# Link against a system-provided libc++abi
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "system-libcxxabi")
add_library(libcxx-abi-headers INTERFACE)
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}" "cxxabi.h;__cxxabi_config.h")
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXX_BUILDING_LIBCXXABI")
import_shared_library(libcxx-abi-shared c++abi)
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" c++abi)
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
# Link against a system-provided libcxxrt
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "libcxxrt")
# libcxxrt does not provide aligned new and delete operators
# TODO: We're keeping this for backwards compatibility, but this doesn't belong here.
set(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON)
if(NOT LIBCXX_CXX_ABI_INCLUDE_PATHS)
message(STATUS "LIBCXX_CXX_ABI_INCLUDE_PATHS not set, using /usr/include/c++/v1")
set(LIBCXX_CXX_ABI_INCLUDE_PATHS "/usr/include/c++/v1")
endif()
add_library(libcxx-abi-headers INTERFACE)
import_private_headers(libcxx-abi-headers "${LIBCXX_CXX_ABI_INCLUDE_PATHS}"
"cxxabi.h;unwind.h;unwind-arm.h;unwind-itanium.h")
target_compile_definitions(libcxx-abi-headers INTERFACE "-DLIBCXXRT")
import_shared_library(libcxx-abi-shared cxxrt)
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
import_static_library(libcxx-abi-static "${LIBCXX_CXX_ABI_LIBRARY_PATH}" cxxrt)
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
# Link against a system-provided vcruntime
# FIXME: Figure out how to configure the ABI library on Windows.
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "vcruntime")
add_library(libcxx-abi-headers INTERFACE)
add_library(libcxx-abi-shared INTERFACE)
add_library(libcxx-abi-static INTERFACE)
# Don't link against any ABI library
elseif ("${LIBCXX_CXX_ABI}" STREQUAL "none")
add_library(libcxx-abi-headers INTERFACE)
target_compile_definitions(libcxx-abi-headers INTERFACE "-D_LIBCPP_BUILDING_HAS_NO_ABI_LIBRARY")
add_library(libcxx-abi-shared INTERFACE)
target_link_libraries(libcxx-abi-shared INTERFACE libcxx-abi-headers)
add_library(libcxx-abi-static INTERFACE)
target_link_libraries(libcxx-abi-static INTERFACE libcxx-abi-headers)
endif()

View File

@ -0,0 +1,254 @@
# HandleLibcxxFlags - A set of macros used to setup the flags used to compile
# and link libc++. These macros add flags to the following CMake variables.
# - LIBCXX_COMPILE_FLAGS: flags used to compile libc++
# - LIBCXX_LINK_FLAGS: flags used to link libc++
# - LIBCXX_LIBRARIES: libraries to link libc++ to.
include(CheckCXXCompilerFlag)
unset(add_flag_if_supported)
# Mangle the name of a compiler flag into a valid CMake identifier.
# Ex: --std=c++11 -> STD_EQ_CXX11
macro(mangle_name str output)
string(STRIP "${str}" strippedStr)
string(REGEX REPLACE "^/" "" strippedStr "${strippedStr}")
string(REGEX REPLACE "^-+" "" strippedStr "${strippedStr}")
string(REGEX REPLACE "-+$" "" strippedStr "${strippedStr}")
string(REPLACE "-" "_" strippedStr "${strippedStr}")
string(REPLACE ":" "_COLON_" strippedStr "${strippedStr}")
string(REPLACE "=" "_EQ_" strippedStr "${strippedStr}")
string(REPLACE "+" "X" strippedStr "${strippedStr}")
string(TOUPPER "${strippedStr}" ${output})
endmacro()
# Remove a list of flags from all CMake variables that affect compile flags.
# This can be used to remove unwanted flags specified on the command line
# or added in other parts of LLVM's cmake configuration.
macro(remove_flags)
foreach(var ${ARGN})
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}")
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "${var}" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "${var}" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
string(REPLACE "${var}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "${var}" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
string(REPLACE "${var}" "" CMAKE_SHARED_MODULE_FLAGS "${CMAKE_SHARED_MODULE_FLAGS}")
remove_definitions(${var})
endforeach()
endmacro(remove_flags)
macro(check_flag_supported flag)
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
endmacro()
macro(append_flags DEST)
foreach(value ${ARGN})
list(APPEND ${DEST} ${value})
list(APPEND ${DEST} ${value})
endforeach()
endmacro()
# If the specified 'condition' is true then append the specified list of flags to DEST
macro(append_flags_if condition DEST)
if (${condition})
list(APPEND ${DEST} ${ARGN})
endif()
endmacro()
# Add each flag in the list specified by DEST if that flag is supported by the current compiler.
macro(append_flags_if_supported DEST)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
append_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${DEST} ${flag})
endforeach()
endmacro()
# Add a macro definition if condition is true.
macro(define_if condition def)
if (${condition})
add_definitions(${def})
endif()
endmacro()
# Add a macro definition if condition is not true.
macro(define_if_not condition def)
if (NOT ${condition})
add_definitions(${def})
endif()
endmacro()
# Add a macro definition to the __config_site file if the specified condition
# is 'true'. Note that '-D${def}' is not added. Instead it is expected that
# the build include the '__config_site' header.
macro(config_define_if condition def)
if (${condition})
set(${def} ON)
endif()
endmacro()
macro(config_define_if_not condition def)
if (NOT ${condition})
set(${def} ON)
endif()
endmacro()
macro(config_define value def)
set(${def} ${value})
endmacro()
# Add a list of flags to all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS',
# 'LIBCXX_COMPILE_FLAGS' and 'LIBCXX_LINK_FLAGS'.
macro(add_target_flags)
foreach(value ${ARGN})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${value}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${value}")
list(APPEND LIBCXX_COMPILE_FLAGS ${value})
list(APPEND LIBCXX_LINK_FLAGS ${value})
endforeach()
endmacro()
# If the specified 'condition' is true then add a list of flags to
# all of 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXX_COMPILE_FLAGS'
# and 'LIBCXX_LINK_FLAGS'.
macro(add_target_flags_if condition)
if (${condition})
add_target_flags(${ARGN})
endif()
endmacro()
# Add all the flags supported by the compiler to all of
# 'CMAKE_CXX_FLAGS', 'CMAKE_C_FLAGS', 'LIBCXX_COMPILE_FLAGS'
# and 'LIBCXX_LINK_FLAGS'.
macro(add_target_flags_if_supported)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
add_target_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
endforeach()
endmacro()
# Add a specified list of flags to both 'LIBCXX_COMPILE_FLAGS' and
# 'LIBCXX_LINK_FLAGS'.
macro(add_flags)
foreach(value ${ARGN})
list(APPEND LIBCXX_COMPILE_FLAGS ${value})
list(APPEND LIBCXX_LINK_FLAGS ${value})
endforeach()
endmacro()
# If the specified 'condition' is true then add a list of flags to both
# 'LIBCXX_COMPILE_FLAGS' and 'LIBCXX_LINK_FLAGS'.
macro(add_flags_if condition)
if (${condition})
add_flags(${ARGN})
endif()
endmacro()
# Add each flag in the list to LIBCXX_COMPILE_FLAGS and LIBCXX_LINK_FLAGS
# if that flag is supported by the current compiler.
macro(add_flags_if_supported)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
add_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
endforeach()
endmacro()
# Add a list of flags to 'LIBCXX_COMPILE_FLAGS'.
macro(add_compile_flags)
foreach(f ${ARGN})
list(APPEND LIBCXX_COMPILE_FLAGS ${f})
endforeach()
endmacro()
# If 'condition' is true then add the specified list of flags to
# 'LIBCXX_COMPILE_FLAGS'
macro(add_compile_flags_if condition)
if (${condition})
add_compile_flags(${ARGN})
endif()
endmacro()
# For each specified flag, add that flag to 'LIBCXX_COMPILE_FLAGS' if the
# flag is supported by the C++ compiler.
macro(add_compile_flags_if_supported)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
add_compile_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
endforeach()
endmacro()
# Add a list of flags to 'LIBCXX_LINK_FLAGS'.
macro(add_link_flags)
foreach(f ${ARGN})
list(APPEND LIBCXX_LINK_FLAGS ${f})
endforeach()
endmacro()
# If 'condition' is true then add the specified list of flags to
# 'LIBCXX_LINK_FLAGS'
macro(add_link_flags_if condition)
if (${condition})
add_link_flags(${ARGN})
endif()
endmacro()
# For each specified flag, add that flag to 'LIBCXX_LINK_FLAGS' if the
# flag is supported by the C++ compiler.
macro(add_link_flags_if_supported)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
add_link_flags_if(CXX_SUPPORTS_${flagname}_FLAG ${flag})
endforeach()
endmacro()
# Add a list of libraries or link flags to 'LIBCXX_LIBRARIES'.
macro(add_library_flags)
foreach(lib ${ARGN})
list(APPEND LIBCXX_LIBRARIES ${lib})
endforeach()
endmacro()
# if 'condition' is true then add the specified list of libraries and flags
# to 'LIBCXX_LIBRARIES'.
macro(add_library_flags_if condition)
if(${condition})
add_library_flags(${ARGN})
endif()
endmacro()
# Turn a comma separated CMake list into a space separated string.
macro(split_list listname)
string(REPLACE ";" " " ${listname} "${${listname}}")
endmacro()
# For each specified flag, add that link flag to the provided target.
# The flags are added with the given visibility, i.e. PUBLIC|PRIVATE|INTERFACE.
function(target_add_link_flags_if_supported target visibility)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
if (CXX_SUPPORTS_${flagname}_FLAG)
target_link_libraries(${target} ${visibility} ${flag})
endif()
endforeach()
endfunction()
# For each specified flag, add that compile flag to the provided target.
# The flags are added with the given visibility, i.e. PUBLIC|PRIVATE|INTERFACE.
function(target_add_compile_flags_if_supported target visibility)
foreach(flag ${ARGN})
mangle_name("${flag}" flagname)
check_cxx_compiler_flag("${flag}" "CXX_SUPPORTS_${flagname}_FLAG")
if (CXX_SUPPORTS_${flagname}_FLAG)
target_compile_options(${target} ${visibility} ${flag})
endif()
endforeach()
endfunction()

View File

@ -0,0 +1,18 @@
# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage )
string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource )
if( _insource )
message( SEND_ERROR "${_errorMessage}" )
message( FATAL_ERROR
"In-source builds are not allowed.
CMake would overwrite the makefiles distributed with Compiler-RT.
Please create a directory and run cmake from there, passing the path
to this source directory as the last argument.
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'.
Please delete them."
)
endif( _insource )
endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD )

View File

@ -0,0 +1,2 @@
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(CMAKE_CXX_COMPILER_TARGET "aarch64-linux-gnu" CACHE STRING "")

View File

@ -0,0 +1,19 @@
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "")
set(CMAKE_C_FLAGS "-D__LIBC_NO_CPP_MATH_OVERLOADS__" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-D__LIBC_NO_CPP_MATH_OVERLOADS__" CACHE STRING "")
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,-G -Wl,-bcdtors:all:-2147483548:s" CACHE STRING "")
set(CMAKE_AR "/usr/bin/ar" CACHE FILEPATH "")
set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(LIBCXX_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(LIBCXX_ABI_VERSION "1" CACHE STRING "")
set(LIBCXX_ENABLE_ABI_LINKER_SCRIPT OFF CACHE BOOL "")
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
set(LIBCXX_ENABLE_STATIC OFF CACHE BOOL "")
set(LIBCXXABI_ENABLE_SHARED ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_STATIC OFF CACHE BOOL "")
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(LIBUNWIND_ENABLE_SHARED ON CACHE BOOL "")
set(LIBUNWIND_ENABLE_STATIC OFF CACHE BOOL "")

View File

@ -0,0 +1,38 @@
# Use CMake's built-in Android NDK support. This will also use the compiler from
# the NDK.
set(CMAKE_ANDROID_NDK "$ENV{ANDROID_NDK_HOME}" CACHE STRING "")
set(CMAKE_SYSTEM_NAME Android CACHE STRING "")
# Default architecture and Android API level. Selecting a much earlier API may
# require adding a toybox build to the device's PATH.
set(CMAKE_ANDROID_ARCH_ABI "x86_64" CACHE STRING "")
set(CMAKE_SYSTEM_VERSION 21 CACHE STRING "")
# Rename libc++.so to libc++_shared.so to ensure that it doesn't interfere with
# the libc++.so on the device, then use LD_LIBRARY_PATH to point test
# executables at the library. Also rename the static library for consistency
# and to help prevent -lc++ from linking libc++.a.
set(LIBCXX_SHARED_OUTPUT_NAME c++_shared CACHE STRING "")
set(LIBCXX_STATIC_OUTPUT_NAME c++_static CACHE STRING "")
# Use a different C++ namespace for the NDK libc++_shared.so to help avoid
# symbol conflicts on older versions of Android.
set(LIBCXX_ABI_NAMESPACE __test CACHE STRING "")
# The build doesn't add a suffix to an Android shared object filename, so it
# writes both a libc++_shared.so ELF file and a libc++_shared.so linker script
# to the same output path (the script clobbers the binary). Turn off the linker
# script.
set(LIBCXX_ENABLE_ABI_LINKER_SCRIPT OFF CACHE BOOL "")
set(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
# Use adb to push tests to a locally-connected device (e.g. emulator) and run them.
set(LIBCXX_TEST_CONFIG "llvm-libc++-android-ndk.cfg.in" CACHE STRING "")
set(LIBCXXABI_TEST_CONFIG "llvm-libc++abi-android-ndk.cfg.in" CACHE STRING "")
# CMAKE_SOURCE_DIR refers to the "<monorepo>/runtimes" directory.
set(LIBCXX_EXECUTOR "${CMAKE_SOURCE_DIR}/../libcxx/utils/adb_run.py" CACHE STRING "")
set(LIBCXXABI_EXECUTOR "${LIBCXX_EXECUTOR}" CACHE STRING "")

View File

@ -0,0 +1,21 @@
set(CMAKE_BUILD_TYPE MinSizeRel CACHE STRING "")
set(CMAKE_POSITION_INDEPENDENT_CODE OFF CACHE BOOL "")
set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "")
set(LIBCXX_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(LIBCXX_ABI_VERSION "1" CACHE STRING "")
set(LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
set(LIBCXX_CXX_ABI libcxxabi CACHE STRING "")
set(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS ON CACHE BOOL "")
set(LIBCXX_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
set(LIBCXXABI_HERMETIC_STATIC_LIBRARY ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(LIBCXXABI_ENABLE_FORGIVING_DYNAMIC_CAST ON CACHE BOOL "")
set(LIBCXX_TEST_CONFIG "apple-libc++-shared.cfg.in" CACHE STRING "")
set(LIBCXXABI_TEST_CONFIG "apple-libc++abi-shared.cfg.in" CACHE STRING "")
set(LIBCXX_TEST_PARAMS "stdlib=apple-libc++" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1,4 @@
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(CMAKE_CXX_COMPILER_TARGET "armv7l-linux-gnueabihf" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-marm" CACHE STRING "")
set(CMAKE_C_FLAGS "-marm" CACHE STRING "")

View File

@ -0,0 +1,6 @@
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(CMAKE_CXX_COMPILER_TARGET "armv7l-linux-gnueabihf" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-mthumb" CACHE STRING "")
set(CMAKE_C_FLAGS "-mthumb" CACHE STRING "")
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
set(LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")

View File

@ -0,0 +1,4 @@
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(CMAKE_CXX_COMPILER_TARGET "armv8l-linux-gnueabihf" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-marm" CACHE STRING "")
set(CMAKE_C_FLAGS "-marm" CACHE STRING "")

View File

@ -0,0 +1,6 @@
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(CMAKE_CXX_COMPILER_TARGET "armv8l-linux-gnueabihf" CACHE STRING "")
set(CMAKE_CXX_FLAGS "-mthumb" CACHE STRING "")
set(CMAKE_C_FLAGS "-mthumb" CACHE STRING "")
set(LIBCXX_ENABLE_EXCEPTIONS OFF CACHE BOOL "")
set(LIBCXXABI_ENABLE_EXCEPTIONS OFF CACHE BOOL "")

View File

@ -0,0 +1,9 @@
set(CMAKE_BUILD_TYPE Release CACHE STRING "")
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "")
set(LIBCXX_ENABLE_ASSERTIONS OFF CACHE BOOL "")
set(LIBCXX_ABI_VERSION "1" CACHE STRING "")
set(LIBCXX_ENABLE_STATIC ON CACHE BOOL "")
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
set(LIBCXX_CXX_ABI libcxxrt CACHE STRING "")
set(LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "")

View File

@ -0,0 +1 @@
set(LIBCXX_ABI_UNSTABLE ON CACHE BOOL "")

View File

@ -0,0 +1,3 @@
set(LLVM_USE_SANITIZER "Address" CACHE STRING "")
# This is a temporary (hopefully) workaround for an ASan issue (see https://llvm.org/D119410).
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -asan-use-private-alias=1" CACHE INTERNAL "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_ENABLE_ASSERTIONS ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_ASSERTIONS ON CACHE BOOL "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "std=c++03" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "std=c++11" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "std=c++14" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "std=c++17" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "std=c++20" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "std=c++2b" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1 @@
set(LIBCXX_ENABLE_DEBUG_MODE ON CACHE BOOL "")

View File

@ -0,0 +1,12 @@
# Build a libc++ shared library, but merge libc++abi and libunwind into it.
set(LIBCXX_ENABLE_SHARED ON CACHE BOOL "")
set(LIBCXX_ENABLE_ABI_LINKER_SCRIPT OFF CACHE BOOL "")
set(LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
set(LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_SHARED OFF CACHE BOOL "")
set(LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_STATIC_LIBRARY ON CACHE BOOL "")
set(LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "enable_modules=True" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1 @@
set(LLVM_USE_SANITIZER "MemoryWithOrigins" CACHE STRING "")

View File

@ -0,0 +1,2 @@
set(LIBCXX_TEST_PARAMS "enable_experimental=False" CACHE STRING "")
set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")

View File

@ -0,0 +1 @@
set(LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "")

Some files were not shown because too many files have changed in this diff Show More