[libc-commits] [libc] [libc] NVPTX Profiling Draft (PR #92009)

via libc-commits libc-commits at lists.llvm.org
Thu May 23 09:05:44 PDT 2024


https://github.com/jameshu15869 updated https://github.com/llvm/llvm-project/pull/92009

>From e55e9b6b8c92247288f8fd8e1431f80e0d2d91b3 Mon Sep 17 00:00:00 2001
From: jameshu15869 <jhudson15869 at gmail.com>
Date: Sat, 11 May 2024 17:19:54 -0400
Subject: [PATCH 1/6] initial nvptx microbenchmarking infrastructure

---
 libc/benchmarks/CMakeLists.txt                | 416 +++++++++---------
 libc/benchmarks/gpu/BenchmarkLogger.cpp       |  89 ++++
 libc/benchmarks/gpu/BenchmarkLogger.h         |  27 ++
 libc/benchmarks/gpu/CMakeLists.txt            | 183 ++++++++
 libc/benchmarks/gpu/LibcGpuBenchmark.cpp      |  70 +++
 libc/benchmarks/gpu/LibcGpuBenchmark.h        | 122 +++++
 libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp  |   6 +
 libc/benchmarks/gpu/src/CMakeLists.txt        |   2 +
 libc/benchmarks/gpu/src/ctype/CMakeLists.txt  |  21 +
 .../gpu/src/ctype/isalnum_benchmark.cpp       |  22 +
 .../gpu/src/ctype/isalpha_benchmark.cpp       |   9 +
 libc/benchmarks/gpu/src/math/CMakeLists.txt   |   0
 libc/benchmarks/gpu/timing/CMakeLists.txt     |  12 +
 .../gpu/timing/nvptx/CMakeLists.txt           |   7 +
 libc/benchmarks/gpu/timing/nvptx/timing.h     | 108 +++++
 libc/benchmarks/gpu/timing/timing.h           |  22 +
 16 files changed, 911 insertions(+), 205 deletions(-)
 create mode 100644 libc/benchmarks/gpu/BenchmarkLogger.cpp
 create mode 100644 libc/benchmarks/gpu/BenchmarkLogger.h
 create mode 100644 libc/benchmarks/gpu/CMakeLists.txt
 create mode 100644 libc/benchmarks/gpu/LibcGpuBenchmark.cpp
 create mode 100644 libc/benchmarks/gpu/LibcGpuBenchmark.h
 create mode 100644 libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp
 create mode 100644 libc/benchmarks/gpu/src/CMakeLists.txt
 create mode 100644 libc/benchmarks/gpu/src/ctype/CMakeLists.txt
 create mode 100644 libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp
 create mode 100644 libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp
 create mode 100644 libc/benchmarks/gpu/src/math/CMakeLists.txt
 create mode 100644 libc/benchmarks/gpu/timing/CMakeLists.txt
 create mode 100644 libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt
 create mode 100644 libc/benchmarks/gpu/timing/nvptx/timing.h
 create mode 100644 libc/benchmarks/gpu/timing/timing.h

diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt
index 4978da65850cc..a802e653a091e 100644
--- a/libc/benchmarks/CMakeLists.txt
+++ b/libc/benchmarks/CMakeLists.txt
@@ -1,205 +1,211 @@
-find_package(Threads)
-
-set(LLVM_LINK_COMPONENTS
-  Support
-  TargetParser
-  )
-
-#==============================================================================
-# Add Unit Testing Support
-#==============================================================================
-
-function(add_libc_benchmark_unittest target_name)
-  if(NOT LLVM_INCLUDE_TESTS)
-    return()
-  endif()
-
-  cmake_parse_arguments(
-    "LIBC_BENCHMARKS_UNITTEST"
-    "" # No optional arguments
-    "SUITE" # Single value arguments
-    "SRCS;DEPENDS" # Multi-value arguments
-    ${ARGN}
-  )
-
-  add_executable(${target_name}
-    EXCLUDE_FROM_ALL
-    ${LIBC_BENCHMARKS_UNITTEST_SRCS}
-  )
-  target_link_libraries(${target_name}
-    PRIVATE
-    llvm_gtest_main
-    llvm_gtest
-    ${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
-  )
-  llvm_update_compile_flags(${target_name})
-
-  add_custom_command(
-    TARGET ${target_name}
-    POST_BUILD
-    COMMAND $<TARGET_FILE:${target_name}>
-  )
-  add_dependencies(libc-benchmark-util-tests ${target_name})
-endfunction()
-
-#==============================================================================
-# Build Google Benchmark for libc
-#==============================================================================
-
-include(ExternalProject)
-ExternalProject_Add(google-benchmark-libc
-        EXCLUDE_FROM_ALL ON
-        PREFIX google-benchmark-libc
-        SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
-        INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
-        CMAKE_CACHE_ARGS
-          -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
-          -DBENCHMARK_ENABLE_LTO:BOOL=OFF
-          -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
-          -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
-          -DBENCHMARK_FORCE_WERROR:BOOL=OFF
-          -DBENCHMARK_USE_LIBCXX:BOOL=OFF
-          -DCMAKE_BUILD_TYPE:STRING=Release
-
-          -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
-          -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
-          -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-          -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-          -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
-          -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
-
-          -DBUILD_SHARED_LIBS:BOOL=OFF
-          -DCMAKE_EXE_LINKER_FLAGS:STRING=-static
-
-          -DCMAKE_CXX_STANDARD:STRING=14
-          -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-        )
-
-add_custom_target(libc-benchmark-util-tests)
-
-# libc-benchmark
-add_library(libc-benchmark
-    STATIC
-    EXCLUDE_FROM_ALL
-    LibcBenchmark.cpp
-    LibcBenchmark.h
-)
-
-target_include_directories(libc-benchmark
-    PUBLIC ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}
-)
-target_link_libraries(libc-benchmark
-    PUBLIC
-    benchmark::benchmark
-    LLVMSupport
-    LLVMTargetParser
-    Threads::Threads
-)
-add_dependencies(libc-benchmark google-benchmark-libc)
-llvm_update_compile_flags(libc-benchmark)
-
-add_libc_benchmark_unittest(libc-benchmark-test
-    SRCS LibcBenchmarkTest.cpp
-    DEPENDS libc-benchmark
-)
-
-# libc-memory-benchmark
-add_library(libc-memory-benchmark
-    STATIC
-    EXCLUDE_FROM_ALL
-    LibcMemoryBenchmark.cpp
-    LibcMemoryBenchmark.h
-    LibcFunctionPrototypes.h
-    MemorySizeDistributions.cpp
-    MemorySizeDistributions.h
-)
-target_include_directories(libc-memory-benchmark
-    PUBLIC
-    ${CMAKE_CURRENT_SOURCE_DIR}
-)
-target_link_libraries(libc-memory-benchmark
-    PUBLIC
-    libc-benchmark
-)
-llvm_update_compile_flags(libc-memory-benchmark)
-
-add_libc_benchmark_unittest(libc-memory-benchmark-test
-    SRCS LibcMemoryBenchmarkTest.cpp
-    DEPENDS libc-memory-benchmark
-)
-
-# json
-add_library(json
-    STATIC
-    EXCLUDE_FROM_ALL
-    JSON.cpp
-    JSON.h
-)
-target_link_libraries(json PUBLIC libc-memory-benchmark)
-llvm_update_compile_flags(json)
-
-add_libc_benchmark_unittest(json-test
-    SRCS JSONTest.cpp
-    DEPENDS json
-)
-
-#==============================================================================
-# Benchmarking tool
-#==============================================================================
-
-# Benchmark all implementations that can run on the target CPU.
-function(add_libc_multi_impl_benchmark name)
-  get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
-  foreach(fq_config_name IN LISTS fq_implementations)
-    get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)
-    cpu_supports(can_run "${required_cpu_features}")
-    if(can_run)
-        set(benchmark_name ${fq_config_name}_benchmark)
-        add_executable(${benchmark_name}
-            EXCLUDE_FROM_ALL
-            LibcMemoryBenchmarkMain.cpp
-        )
-        get_target_property(entrypoint_object_file ${fq_config_name} "OBJECT_FILE_RAW")
-        target_link_libraries(${benchmark_name} PUBLIC json ${entrypoint_object_file})
-        string(TOUPPER ${name} name_upper)
-        target_compile_definitions(${benchmark_name} PRIVATE "-DLIBC_BENCHMARK_FUNCTION_${name_upper}=LIBC_NAMESPACE::${name}" "-DLIBC_BENCHMARK_FUNCTION_NAME=\"${fq_config_name}\"")
-        llvm_update_compile_flags(${benchmark_name})
-    else()
-      message(STATUS "Skipping benchmark for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")
-    endif()
-  endforeach()
-endfunction()
-
-add_libc_multi_impl_benchmark(bcmp)
-add_libc_multi_impl_benchmark(bzero)
-add_libc_multi_impl_benchmark(memcmp)
-add_libc_multi_impl_benchmark(memcpy)
-add_libc_multi_impl_benchmark(memmove)
-add_libc_multi_impl_benchmark(memset)
-
-#==============================================================================
-# Google Benchmarking tool
-#==============================================================================
-
-# This target uses the Google Benchmark facility to report throughput for llvm
-# libc memory functions compiled for the host machine. This is useful to
-# continuously monitor the performance of the memory functions.
-add_executable(libc.benchmarks.memory_functions.opt_host
-  EXCLUDE_FROM_ALL
-  LibcMemoryGoogleBenchmarkMain.cpp
-  LibcDefaultImplementations.cpp
-)
-target_link_libraries(libc.benchmarks.memory_functions.opt_host
-  PRIVATE
-  libc-memory-benchmark
-  libc.src.string.memcmp_opt_host.__internal__
-  libc.src.string.bcmp_opt_host.__internal__
-  libc.src.string.memcpy_opt_host.__internal__
-  libc.src.string.memset_opt_host.__internal__
-  libc.src.string.bzero_opt_host.__internal__
-  libc.src.string.memmove_opt_host.__internal__
-  benchmark_main
-)
-llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host)
-
-add_subdirectory(automemcpy)
+if(NOT LIBC_TARGET_OS_IS_GPU)
+	find_package(Threads)
+
+	set(LLVM_LINK_COMPONENTS
+	  Support
+	  TargetParser
+	  )
+
+	#==============================================================================
+	# Add Unit Testing Support
+	#==============================================================================
+
+	function(add_libc_benchmark_unittest target_name)
+	  if(NOT LLVM_INCLUDE_TESTS)
+	    return()
+	  endif()
+
+	  cmake_parse_arguments(
+	    "LIBC_BENCHMARKS_UNITTEST"
+	    "" # No optional arguments
+	    "SUITE" # Single value arguments
+	    "SRCS;DEPENDS" # Multi-value arguments
+	    ${ARGN}
+	  )
+
+	  add_executable(${target_name}
+	    EXCLUDE_FROM_ALL
+	    ${LIBC_BENCHMARKS_UNITTEST_SRCS}
+	  )
+	  target_link_libraries(${target_name}
+	    PRIVATE
+	    llvm_gtest_main
+	    llvm_gtest
+	    ${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
+	  )
+	  llvm_update_compile_flags(${target_name})
+
+	  add_custom_command(
+	    TARGET ${target_name}
+	    POST_BUILD
+	    COMMAND $<TARGET_FILE:${target_name}>
+	  )
+	  add_dependencies(libc-benchmark-util-tests ${target_name})
+	endfunction()
+
+	#==============================================================================
+	# Build Google Benchmark for libc
+	#==============================================================================
+
+	include(ExternalProject)
+	ExternalProject_Add(google-benchmark-libc
+		EXCLUDE_FROM_ALL ON
+		PREFIX google-benchmark-libc
+		SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
+		INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
+		CMAKE_CACHE_ARGS
+		  -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
+		  -DBENCHMARK_ENABLE_LTO:BOOL=OFF
+		  -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
+		  -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
+		  -DBENCHMARK_FORCE_WERROR:BOOL=OFF
+		  -DBENCHMARK_USE_LIBCXX:BOOL=OFF
+		  -DCMAKE_BUILD_TYPE:STRING=Release
+
+		  -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
+		  -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
+		  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+		  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+		  -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+		  -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
+
+		  -DBUILD_SHARED_LIBS:BOOL=OFF
+		  -DCMAKE_EXE_LINKER_FLAGS:STRING=-static
+
+		  -DCMAKE_CXX_STANDARD:STRING=14
+		  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+		)
+
+	add_custom_target(libc-benchmark-util-tests)
+
+	# libc-benchmark
+	add_library(libc-benchmark
+	    STATIC
+	    EXCLUDE_FROM_ALL
+	    LibcBenchmark.cpp
+	    LibcBenchmark.h
+	)
+
+	target_include_directories(libc-benchmark
+	    PUBLIC ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}
+	)
+	target_link_libraries(libc-benchmark
+	    PUBLIC
+	    benchmark::benchmark
+            LLVMSupport
+	    LLVMTargetParser
+	    Threads::Threads
+	)
+	add_dependencies(libc-benchmark google-benchmark-libc)
+	llvm_update_compile_flags(libc-benchmark)
+
+	add_libc_benchmark_unittest(libc-benchmark-test
+	    SRCS LibcBenchmarkTest.cpp
+	    DEPENDS libc-benchmark
+	)
+
+	# libc-memory-benchmark
+	add_library(libc-memory-benchmark
+	    STATIC
+	    EXCLUDE_FROM_ALL
+	    LibcMemoryBenchmark.cpp
+	    LibcMemoryBenchmark.h
+	    LibcFunctionPrototypes.h
+	    MemorySizeDistributions.cpp
+	    MemorySizeDistributions.h
+	)
+	target_include_directories(libc-memory-benchmark
+	    PUBLIC
+	    ${CMAKE_CURRENT_SOURCE_DIR}
+	)
+	target_link_libraries(libc-memory-benchmark
+	    PUBLIC
+	    libc-benchmark
+	)
+	llvm_update_compile_flags(libc-memory-benchmark)
+
+	add_libc_benchmark_unittest(libc-memory-benchmark-test
+	    SRCS LibcMemoryBenchmarkTest.cpp
+	    DEPENDS libc-memory-benchmark
+	)
+
+	# json
+	add_library(json
+	    STATIC
+	    EXCLUDE_FROM_ALL
+	    JSON.cpp
+	    JSON.h
+	)
+	target_link_libraries(json PUBLIC libc-memory-benchmark)
+	llvm_update_compile_flags(json)
+
+	add_libc_benchmark_unittest(json-test
+	    SRCS JSONTest.cpp
+	    DEPENDS json
+	)
+
+	#==============================================================================
+	# Benchmarking tool
+	#==============================================================================
+
+	# Benchmark all implementations that can run on the target CPU.
+	function(add_libc_multi_impl_benchmark name)
+	  get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
+	  foreach(fq_config_name IN LISTS fq_implementations)
+	    get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)
+	    cpu_supports(can_run "${required_cpu_features}")
+	    if(can_run)
+		set(benchmark_name ${fq_config_name}_benchmark)
+		add_executable(${benchmark_name}
+		    EXCLUDE_FROM_ALL
+		    LibcMemoryBenchmarkMain.cpp
+		)
+		get_target_property(entrypoint_object_file ${fq_config_name} "OBJECT_FILE_RAW")
+		target_link_libraries(${benchmark_name} PUBLIC json ${entrypoint_object_file})
+		string(TOUPPER ${name} name_upper)
+		target_compile_definitions(${benchmark_name} PRIVATE "-DLIBC_BENCHMARK_FUNCTION_${name_upper}=LIBC_NAMESPACE::${name}" "-DLIBC_BENCHMARK_FUNCTION_NAME=\"${fq_config_name}\"")
+		llvm_update_compile_flags(${benchmark_name})
+	    else()
+	      message(STATUS "Skipping benchmark for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")
+	    endif()
+	  endforeach()
+	endfunction()
+
+	add_libc_multi_impl_benchmark(bcmp)
+	add_libc_multi_impl_benchmark(bzero)
+	add_libc_multi_impl_benchmark(memcmp)
+	add_libc_multi_impl_benchmark(memcpy)
+	add_libc_multi_impl_benchmark(memmove)
+	add_libc_multi_impl_benchmark(memset)
+
+	#==============================================================================
+	# Google Benchmarking tool
+	#==============================================================================
+
+	# This target uses the Google Benchmark facility to report throughput for llvm
+	# libc memory functions compiled for the host machine. This is useful to
+	# continuously monitor the performance of the memory functions.
+	add_executable(libc.benchmarks.memory_functions.opt_host
+	  EXCLUDE_FROM_ALL
+	  LibcMemoryGoogleBenchmarkMain.cpp
+	  LibcDefaultImplementations.cpp
+	)
+	target_link_libraries(libc.benchmarks.memory_functions.opt_host
+	  PRIVATE
+	  libc-memory-benchmark
+	  libc.src.string.memcmp_opt_host.__internal__
+	  libc.src.string.bcmp_opt_host.__internal__
+	  libc.src.string.memcpy_opt_host.__internal__
+	  libc.src.string.memset_opt_host.__internal__
+	  libc.src.string.bzero_opt_host.__internal__
+	  libc.src.string.memmove_opt_host.__internal__
+	  benchmark_main
+	)
+	llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host)
+
+	add_subdirectory(automemcpy)
+endif()
+
+if(LIBC_TARGET_OS_IS_GPU)
+	add_subdirectory(gpu)
+endif()
diff --git a/libc/benchmarks/gpu/BenchmarkLogger.cpp b/libc/benchmarks/gpu/BenchmarkLogger.cpp
new file mode 100644
index 0000000000000..94a0d897c9585
--- /dev/null
+++ b/libc/benchmarks/gpu/BenchmarkLogger.cpp
@@ -0,0 +1,89 @@
+#include "benchmarks/gpu/BenchmarkLogger.h"
+#include "src/__support/CPP/string.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/io.h"               // write_to_stderr
+#include "src/__support/big_int.h"                 // is_big_int
+#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
+#include "src/__support/uint128.h"
+
+#include <stdint.h>
+
+namespace LIBC_NAMESPACE {
+namespace libc_gpu_benchmarks {
+
+// cpp::string_view specialization
+template <>
+BenchmarkLogger &BenchmarkLogger::operator<< <cpp::string_view>(cpp::string_view str) {
+  LIBC_NAMESPACE::write_to_stderr(str);
+  return *this;
+}
+
+// cpp::string specialization
+template <> BenchmarkLogger &BenchmarkLogger::operator<< <cpp::string>(cpp::string str) {
+  return *this << static_cast<cpp::string_view>(str);
+}
+
+// const char* specialization
+template <> BenchmarkLogger &BenchmarkLogger::operator<< <const char *>(const char *str) {
+  return *this << cpp::string_view(str);
+}
+
+// char* specialization
+template <> BenchmarkLogger &BenchmarkLogger::operator<< <char *>(char *str) {
+  return *this << cpp::string_view(str);
+}
+
+// char specialization
+template <> BenchmarkLogger &BenchmarkLogger::operator<<(char ch) {
+  return *this << cpp::string_view(&ch, 1);
+}
+
+// bool specialization
+template <> BenchmarkLogger &BenchmarkLogger::operator<<(bool cond) {
+  return *this << (cond ? "true" : "false");
+}
+
+// void * specialization
+template <> BenchmarkLogger &BenchmarkLogger::operator<<(void *addr) {
+  return *this << "0x" << cpp::to_string(reinterpret_cast<uintptr_t>(addr));
+}
+
+template <typename T> BenchmarkLogger &BenchmarkLogger::operator<<(T t) {
+  if constexpr (is_big_int_v<T> ||
+                (cpp::is_integral_v<T> && cpp::is_unsigned_v<T> &&
+                 (sizeof(T) > sizeof(uint64_t)))) {
+    static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt");
+    const IntegerToString<T, radix::Hex::WithPrefix> buffer(t);
+    return *this << buffer.view();
+  } else {
+    return *this << cpp::to_string(t);
+  }
+}
+
+// is_integral specializations
+// char is already specialized to handle character
+template BenchmarkLogger &BenchmarkLogger::operator<< <short>(short);
+template BenchmarkLogger &BenchmarkLogger::operator<< <int>(int);
+template BenchmarkLogger &BenchmarkLogger::operator<< <long>(long);
+template BenchmarkLogger &BenchmarkLogger::operator<< <long long>(long long);
+template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned char>(unsigned char);
+template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned short>(unsigned short);
+template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned int>(unsigned int);
+template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned long>(unsigned long);
+template BenchmarkLogger &
+    BenchmarkLogger::operator<< <unsigned long long>(unsigned long long);
+
+#ifdef LIBC_TYPES_HAS_INT128
+template BenchmarkLogger &BenchmarkLogger::operator<< <__uint128_t>(__uint128_t);
+#endif // LIBC_TYPES_HAS_INT128
+template BenchmarkLogger &BenchmarkLogger::operator<< <UInt<128>>(UInt<128>);
+template BenchmarkLogger &BenchmarkLogger::operator<< <UInt<192>>(UInt<192>);
+template BenchmarkLogger &BenchmarkLogger::operator<< <UInt<256>>(UInt<256>);
+template BenchmarkLogger &BenchmarkLogger::operator<< <UInt<320>>(UInt<320>);
+
+// TODO: Add floating point formatting once it's supported by StringStream.
+
+BenchmarkLogger blog;
+
+} // namespace libc_gpu_benchmarks
+} // namespace LIBC_NAMESPACE
diff --git a/libc/benchmarks/gpu/BenchmarkLogger.h b/libc/benchmarks/gpu/BenchmarkLogger.h
new file mode 100644
index 0000000000000..ed3cc97e59c6d
--- /dev/null
+++ b/libc/benchmarks/gpu/BenchmarkLogger.h
@@ -0,0 +1,27 @@
+//===-- Utilities to log to standard output during tests --------*- 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 LLVM_LIBC_BENCHMARKS_GPU_BENCHMARKLOGGER_H
+#define LLVM_LIBC_BENCHMARKS_GPU_BENCHMARKLOGGER_H
+
+namespace LIBC_NAMESPACE {
+namespace libc_gpu_benchmarks {
+
+// A class to log to standard output in the context of hermetic tests.
+struct BenchmarkLogger {
+  constexpr BenchmarkLogger() = default;
+  template <typename T> BenchmarkLogger &operator<<(T);
+};
+
+// A global TestLogger instance to be used in tests.
+extern BenchmarkLogger blog;
+
+} // namespace libc_gpu_benchmarks
+} // namespace LIBC_NAMESPACE
+
+#endif /* LLVM_LIBC_BENCHMARKS_GPU_BENCHMARKLOGGER_H */
diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt
new file mode 100644
index 0000000000000..a18be27e33573
--- /dev/null
+++ b/libc/benchmarks/gpu/CMakeLists.txt
@@ -0,0 +1,183 @@
+add_subdirectory(timing)
+
+add_custom_target(gpu-benchmark)
+
+function (add_gpu_benchmark test_name)
+  if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)
+    message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")
+    return()
+  endif()
+
+  cmake_parse_arguments(
+    "GPU_BENCHMARK"
+    "" # No optional arguments
+    "SUITE" # Single value arguments
+    "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments
+    ${ARGN}
+  )
+
+  if(NOT GPU_BENCHMARK_SUITE)
+    message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")
+  endif()
+  if(NOT GPU_BENCHMARK_SRCS)
+    message(FATAL_ERROR "The SRCS list for add_gpu_benchmark is missing.")
+  endif()
+
+  get_fq_target_name(${test_name} fq_target_name)
+  get_fq_target_name(${test_name}.libc fq_libc_target_name) # Stores the compiled libc + infrastructure archive to link in
+  get_fq_deps_list(fq_deps_list ${GPU_BENCHMARK_DEPENDS})
+  list(APPEND fq_deps_list
+      # Hermetic tests use the platform's startup object. So, their deps also
+      # have to be collected.
+      libc.startup.${LIBC_TARGET_OS}.crt1
+      # We always add the memory functions objects. This is because the
+      # compiler's codegen can emit calls to the C memory functions.
+      libc.src.string.bcmp
+      libc.src.string.bzero
+      libc.src.string.memcmp
+      libc.src.string.memcpy
+      libc.src.string.memmove
+      libc.src.string.memset
+      libc.src.__support.StringUtil.error_to_string
+  )
+
+  list(REMOVE_DUPLICATES fq_deps_list)
+
+  # TODO: Instead of gathering internal object files from entrypoints,
+  # collect the object files with public names of entrypoints.
+  get_object_files_for_test(
+      link_object_files skipped_entrypoints_list ${fq_deps_list})
+  if(skipped_entrypoints_list)
+    if(LIBC_CMAKE_VERBOSE_LOGGING)
+      set(msg "Skipping hermetic test ${fq_target_name} as it has missing deps: "
+              "${skipped_entrypoints_list}.")
+    endif()
+    return()
+  endif()
+  list(REMOVE_DUPLICATES link_object_files)
+
+  # Make a library of all deps
+  add_library(
+    ${fq_target_name}.__libc__
+    STATIC
+    EXCLUDE_FROM_ALL
+    ${link_object_files}
+  )
+  set_target_properties(${fq_target_name}.__libc__
+      PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+  set_target_properties(${fq_target_name}.__libc__
+      PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)
+
+  set(fq_build_target_name ${fq_target_name}.__build__)
+  add_executable(
+    ${fq_build_target_name}
+    EXCLUDE_FROM_ALL
+    $<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>:${link_object_files}>
+    ${GPU_BENCHMARK_SRCS}
+    ${GPU_BENCHMARK_HDRS}
+  )
+  set_target_properties(${fq_build_target_name}
+    PROPERTIES
+      RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+  )
+
+  _get_hermetic_test_compile_options(compile_options "${GPU_BENCHMARK_COMPILE_OPTIONS}")
+  target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
+  target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})
+  _get_hermetic_test_compile_options(compile_options "${GPU_BENCHMARK_COMPILE_OPTIONS}")
+  target_compile_options(${fq_build_target_name} PRIVATE ${compile_options}) 
+
+  set(link_libraries "")
+  foreach(lib in LISTS GPU_BENCHMARK_LINK_LIBRARIES)
+    if(TARGET ${lib}.hermetic)
+      list(APPEND link_libraries ${lib}.hermetic)
+    else()
+      list(APPEND link_libraries ${lib})
+    endif()
+  endforeach()
+
+  if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
+    target_link_options(${fq_build_target_name} PRIVATE
+      ${LIBC_COMPILE_OPTIONS_DEFAULT}
+      -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto -Wno-multi-gpu
+      "-Wl,-mllvm,-amdgpu-lower-global-ctor-dtor=0" -nostdlib -static
+      "-Wl,-mllvm,-amdhsa-code-object-version=${LIBC_GPU_CODE_OBJECT_VERSION}")
+  elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
+    # We need to use the internal object versions for NVPTX.
+    set(internal_suffix ".__internal__")
+    target_link_options(${fq_build_target_name} PRIVATE
+      ${LIBC_COMPILE_OPTIONS_DEFAULT} -Wno-multi-gpu
+      "-Wl,--suppress-stack-size-warning"
+      -march=${LIBC_GPU_TARGET_ARCHITECTURE} -nostdlib -static
+      "--cuda-path=${LIBC_CUDA_ROOT}")
+  elseif(LIBC_CC_SUPPORTS_NOSTDLIBPP)
+    target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib++ -static)
+  else()
+    # Older version of gcc does not support `nostdlib++` flag.  We use
+    # `nostdlib` and link against libgcc_s, which cannot be linked statically.
+    target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib)
+    list(APPEND link_libraries ${LIBGCC_S_LOCATION})
+  endif()
+
+  # link libraries for the BUILD target (i.e. to compile the test)
+  target_link_libraries(
+    ${fq_build_target_name}
+    PRIVATE
+      libc.startup.${LIBC_TARGET_OS}.crt1${internal_suffix}
+      ${link_libraries}
+      # LibcTest.hermetic
+      LibcGpuBenchmark.hermetic
+      # LibcHermeticTestSupport.hermetic
+      LibcHermeticTestSupport.hermetic
+      # The NVIDIA 'nvlink' linker does not currently support static libraries.
+      $<$<NOT:$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>>:${fq_target_name}.__libc__>)
+
+  add_dependencies(${fq_build_target_name}
+    LibcGpuBenchmark.hermetic
+  ${fq_deps_list})
+
+  # Tests on the GPU require an external loader utility to launch the kernel.
+  if(TARGET libc.utils.gpu.loader)
+    add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
+    get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
+  endif()
+
+  set(test_cmd ${GPU_BENCHMARK_ENV}
+      $<$<BOOL:${LIBC_TARGET_OS_IS_GPU}>:${gpu_loader_exe}> ${CMAKE_CROSSCOMPILING_EMULATOR} ${GPU_BENCHMARK_LOADER_ARGS}
+      $<TARGET_FILE:${fq_build_target_name}> ${GPU_BENCHMARK_ARGS})
+  add_custom_target(
+    ${fq_target_name}
+    COMMAND ${test_cmd}
+    COMMAND_EXPAND_LISTS
+    COMMENT "Running GPU benchmark ${fq_target_name}"
+  )
+
+  # Make this benchmark part of its suite
+  add_dependencies(${GPU_BENCHMARK_SUITE} ${fq_target_name})
+  # Remember to make this benchmark part of the umbrella command
+  add_dependencies(gpu-benchmark ${fq_target_name})
+endfunction(add_gpu_benchmark)
+
+add_unittest_framework_library(
+  LibcGpuBenchmark
+  SRCS
+    LibcGpuBenchmark.cpp
+    LibcGpuBenchmarkMain.cpp
+    BenchmarkLogger.cpp
+  HDRS
+    LibcGpuBenchmark.h
+    BenchmarkLogger.h
+  DEPENDS
+    libc.src.__support.big_int
+    libc.src.__support.c_string
+    libc.src.__support.CPP.string
+    libc.src.__support.CPP.string_view
+    libc.src.__support.CPP.type_traits
+    libc.src.__support.fixed_point.fx_rep
+    libc.src.__support.macros.properties.types
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.uint128
+    libc.benchmarks.gpu.timing.timing
+)
+
+add_subdirectory(src)
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
new file mode 100644
index 0000000000000..d37f5a0a53a70
--- /dev/null
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
@@ -0,0 +1,70 @@
+#include "LibcGpuBenchmark.h"
+
+namespace LIBC_NAMESPACE {
+namespace libc_gpu_benchmarks {
+
+Benchmark *Benchmark::Start = nullptr;
+Benchmark *Benchmark::End = nullptr;
+
+void Benchmark::addBenchmark(Benchmark *B) {
+  if (End == nullptr) {
+    Start = B;
+    End = B;
+    return;
+  }
+
+  End->Next = B;
+  End = B;
+}
+
+int Benchmark::runBenchmarks() {
+  for (Benchmark *B = Start; B != nullptr; B = B->Next) {
+    B->Run();
+  }
+
+  return 0;
+}
+
+BenchmarkResult benchmark(const BenchmarkOptions &Options,
+                          uint64_t (*WrapperFunc)()) {
+  BenchmarkResult Result;
+  RuntimeEstimationProgression REP;
+  size_t TotalIterations = 0;
+  size_t Iterations = Options.InitialIterations;
+  if (Iterations < (uint32_t)1) {
+    Iterations = 1;
+  }
+  size_t Samples = 0;
+  uint64_t BestGuess = 0;
+  uint64_t TotalCycles = 0;
+  for (;;) {
+    uint64_t SampleCycles = 0;
+    for (uint32_t i = 0; i < Iterations; i++) {
+      auto overhead = LIBC_NAMESPACE::overhead();
+      uint64_t result = WrapperFunc() - overhead;
+      SampleCycles += result;
+    }
+
+    Samples++;
+    TotalCycles += SampleCycles;
+    TotalIterations += Iterations;
+    const double ChangeRatio =
+        REP.ComputeImprovement({Iterations, SampleCycles});
+    BestGuess = REP.CurrentEstimation;
+
+    if (Samples >= Options.MaxSamples || Iterations >= Options.MaxIterations) {
+      break;
+    } else if (Samples >= Options.MinSamples && ChangeRatio < Options.Epsilon) {
+      break;
+    }
+
+    Iterations *= Options.ScalingFactor;
+  }
+  Result.Cycles = BestGuess;
+  Result.Samples = Samples;
+  Result.TotalIterations = TotalIterations;
+  return Result;
+};
+
+} // namespace libc_gpu_benchmarks
+} // namespace LIBC_NAMESPACE
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.h b/libc/benchmarks/gpu/LibcGpuBenchmark.h
new file mode 100644
index 0000000000000..ccbbe3629dbda
--- /dev/null
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.h
@@ -0,0 +1,122 @@
+#ifndef LLVM_LIBC_BENCHMARKS_LIBC_GPU_BENCHMARK_H
+#define LLVM_LIBC_BENCHMARKS_LIBC_GPU_BENCHMARK_H
+
+#include "benchmarks/gpu/timing/timing.h"
+
+#include "benchmarks/gpu/BenchmarkLogger.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace LIBC_NAMESPACE {
+
+namespace libc_gpu_benchmarks {
+
+struct BenchmarkOptions {
+  uint32_t InitialIterations = 1;
+  uint32_t MaxIterations = 10000000;
+  uint32_t MinSamples = 4;
+  uint32_t MaxSamples = 1000;
+  double Epsilon = 0.01;
+  double ScalingFactor = 1.4;
+};
+
+struct Measurement {
+  size_t Iterations = 0;
+  uint64_t ElapsedCycles = 0;
+};
+
+class RefinableRuntimeEstimation {
+  uint64_t TotalCycles = 0;
+  size_t TotalIterations = 0;
+
+public:
+  uint64_t Update(const Measurement &M) {
+    TotalCycles += M.ElapsedCycles;
+    TotalIterations += M.Iterations;
+    return TotalCycles / TotalIterations;
+  }
+};
+
+// Tracks the progression of the runtime estimation
+class RuntimeEstimationProgression {
+  RefinableRuntimeEstimation RRE;
+
+public:
+  uint64_t CurrentEstimation = 0;
+
+  double ComputeImprovement(const Measurement &M) {
+    const uint64_t NewEstimation = RRE.Update(M);
+    double Ratio = ((double)CurrentEstimation / NewEstimation) - 1.0;
+
+    // Get absolute value
+    if (Ratio < 0) {
+      Ratio *= -1;
+    }
+
+    CurrentEstimation = NewEstimation;
+    return Ratio;
+  }
+};
+
+struct BenchmarkResult {
+  uint64_t Cycles = 0;
+  size_t Samples = 0;
+  size_t TotalIterations = 0;
+};
+
+BenchmarkResult benchmark(const BenchmarkOptions &Options,
+                          uint64_t (*WrapperFunc)());
+
+class Benchmark {
+  Benchmark *Next = nullptr;
+
+public:
+  virtual ~Benchmark() {}
+  virtual void SetUp() {}
+  virtual void TearDown() {}
+
+  static int runBenchmarks();
+
+protected:
+  static void addBenchmark(Benchmark *);
+
+private:
+  virtual void Run() = 0;
+  virtual const char *getName() const = 0;
+
+  static Benchmark *Start;
+  static Benchmark *End;
+};
+
+class WrapperBenchmark : public Benchmark {
+  using BenchmarkWrapperFunction = uint64_t (*)();
+  BenchmarkWrapperFunction Func;
+  const char *Name;
+
+public:
+  WrapperBenchmark(BenchmarkWrapperFunction Func, char const *Name)
+      : Func(Func), Name(Name) {
+    addBenchmark(this);
+  }
+
+private:
+  void Run() override {
+    BenchmarkOptions Options;
+    auto result = benchmark(Options, Func);
+    constexpr auto GREEN = "\033[32m";
+    constexpr auto RESET = "\033[0m";
+    blog << GREEN << "[ RUN      ] " << RESET << Name << '\n';
+    blog << GREEN << "[       OK ] " << RESET << Name << ": " << result.Cycles
+         << " cycles, " << result.TotalIterations << " iterations\n";
+  }
+  const char *getName() const override { return Name; }
+};
+} // namespace libc_gpu_benchmarks
+} // namespace LIBC_NAMESPACE
+
+#define BENCHMARK(SuiteName, TestName, Func)                                   \
+  LIBC_NAMESPACE::libc_gpu_benchmarks::WrapperBenchmark                        \
+      SuiteName##_##TestName##_Instance(Func, #SuiteName "." #TestName);
+
+#endif
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp b/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp
new file mode 100644
index 0000000000000..c971b00cc9a1b
--- /dev/null
+++ b/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp
@@ -0,0 +1,6 @@
+#include "LibcGpuBenchmark.h"
+
+extern "C" int main(int argc, char **argv, char **envp) {
+  LIBC_NAMESPACE::libc_gpu_benchmarks::Benchmark::runBenchmarks();
+  return 0;
+}
diff --git a/libc/benchmarks/gpu/src/CMakeLists.txt b/libc/benchmarks/gpu/src/CMakeLists.txt
new file mode 100644
index 0000000000000..f15d082e4dd2b
--- /dev/null
+++ b/libc/benchmarks/gpu/src/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(ctype)
+add_subdirectory(math)
diff --git a/libc/benchmarks/gpu/src/ctype/CMakeLists.txt b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
new file mode 100644
index 0000000000000..ab2f6cdf0c7fd
--- /dev/null
+++ b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
@@ -0,0 +1,21 @@
+add_custom_target(libc-gpu-ctype-benchmarks)
+
+add_gpu_benchmark(
+    isalnum_benchmark
+    SUITE
+        libc-gpu-ctype-benchmarks
+    SRCS
+        isalnum_benchmark.cpp
+    DEPENDS
+        libc.src.ctype.isalnum
+)
+
+add_gpu_benchmark(
+    isalpha_benchmark
+    SUITE
+        libc-gpu-ctype-benchmarks
+    SRCS
+        isalpha_benchmark.cpp
+    DEPENDS
+        libc.src.ctype.isalpha
+)
diff --git a/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp b/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp
new file mode 100644
index 0000000000000..8d9c958bb7ed4
--- /dev/null
+++ b/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp
@@ -0,0 +1,22 @@
+#include "benchmarks/gpu/LibcGpuBenchmark.h"
+
+#include "src/ctype/isalnum.h"
+
+uint64_t BM_IsAlnum() {
+  char x = 'c';
+  return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalnum, x);
+}
+BENCHMARK(LlvmLibcIsAlNumGpuBenchmark, IsAlnumWrapper, BM_IsAlnum);
+
+[[gnu::noinline]] static uint64_t single_input_function(int x) {
+  asm volatile("" ::"r"(x)); // prevent the compiler from optimizing out x
+  return x;
+}
+
+uint64_t BM_IsAlnumWithOverhead() {
+  char x = 'c';
+  return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalnum, x) -
+         LIBC_NAMESPACE::latency(single_input_function, 0);
+}
+BENCHMARK(LlvmLibcIsAlNumGpuBenchmark, IsAlnumWithOverhead,
+          BM_IsAlnumWithOverhead);
diff --git a/libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp b/libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp
new file mode 100644
index 0000000000000..2038eb89bc77b
--- /dev/null
+++ b/libc/benchmarks/gpu/src/ctype/isalpha_benchmark.cpp
@@ -0,0 +1,9 @@
+#include "benchmarks/gpu/LibcGpuBenchmark.h"
+
+#include "src/ctype/isalpha.h"
+
+uint64_t BM_IsAlpha() {
+  char x = 'c';
+  return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalpha, x);
+}
+BENCHMARK(LlvmLibcIsAlphaGpuBenchmark, IsAlpha, BM_IsAlpha);
diff --git a/libc/benchmarks/gpu/src/math/CMakeLists.txt b/libc/benchmarks/gpu/src/math/CMakeLists.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/libc/benchmarks/gpu/timing/CMakeLists.txt b/libc/benchmarks/gpu/timing/CMakeLists.txt
new file mode 100644
index 0000000000000..0e6a5a6b47968
--- /dev/null
+++ b/libc/benchmarks/gpu/timing/CMakeLists.txt
@@ -0,0 +1,12 @@
+foreach(target nvptx)
+    add_subdirectory(${target})
+    list(APPEND target_gpu_timing libc.benchmarks.gpu.timing.${target}.${target}_timing)
+endforeach()
+
+add_header_library(
+    timing
+    HDRS
+        timing.h
+    DEPENDS
+        ${target_gpu_timing}
+)
diff --git a/libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt b/libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt
new file mode 100644
index 0000000000000..9958e16206a41
--- /dev/null
+++ b/libc/benchmarks/gpu/timing/nvptx/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_header_library(
+  nvptx_timing
+  HDRS
+    timing.h
+  DEPENDS
+    libc.src.__support.common
+)
diff --git a/libc/benchmarks/gpu/timing/nvptx/timing.h b/libc/benchmarks/gpu/timing/nvptx/timing.h
new file mode 100644
index 0000000000000..008432e6aa1d2
--- /dev/null
+++ b/libc/benchmarks/gpu/timing/nvptx/timing.h
@@ -0,0 +1,108 @@
+//===------------- NVPTX implementation of timing utils ---------*- 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 LLVM_LIBC_UTILS_GPU_TIMING_NVPTX
+#define LLVM_LIBC_UTILS_GPU_TIMING_NVPTX
+
+#include "src/__support/GPU/utils.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+#include <stdint.h>
+
+namespace LIBC_NAMESPACE {
+
+// Returns the overhead associated with calling the profiling region. This
+// allows us to substract the constant-time overhead from the latency to
+// obtain a true result. This can vary with system load.
+[[gnu::noinline]] static uint64_t overhead() {
+  volatile uint32_t x = 1;
+  uint32_t y = x;
+  gpu::sync_threads();
+  uint64_t start = gpu::processor_clock();
+  asm volatile("" ::"r"(y), "llr"(start));
+  uint32_t result = y;
+  asm volatile("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :);
+  uint64_t stop = gpu::processor_clock();
+  gpu::sync_threads();
+  volatile auto storage = result;
+  return stop - start;
+}
+
+// Stimulate a simple function and obtain its latency in clock cycles on the
+// system. This function cannot be inlined or else it will disturb the very
+// deliccate balance of hard-coded dependencies.
+//
+// FIXME: This does not work in general on NVPTX because of further
+// optimizations ptxas performs. The only way to get consistent results is to
+// pass and extra "SHELL:-Xcuda-ptxas -O0" to CMake's compiler flag. This
+// negatively implacts performance but it is at least stable.
+template <typename F, typename T>
+[[gnu::noinline]] static LIBC_INLINE uint64_t latency(F f, T t) {
+  // We need to store the input somewhere to guarantee that the compiler will
+  // not constant propagate it and remove the profiling region.
+  volatile T storage = t;
+  T arg = storage;
+  asm volatile("" ::"r"(arg));
+
+  // Get the current timestamp from the clock.
+  gpu::sync_threads();
+  __nvvm_membar_sys();
+  uint64_t start = gpu::processor_clock();
+
+  // This forces the compiler to load the input argument and run the clock cycle
+  // counter before the profiling region.
+  asm volatile("" ::"r"(arg), "llr"(start));
+
+  // Run the function under test and return its value.
+  auto result = f(arg);
+
+  // This inline assembly performs a no-op which forces the result to both be
+  // used and prevents us from exiting this region before it's complete.
+  asm volatile("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :);
+
+  // Obtain the current timestamp after running the calculation and force
+  // ordering.
+  uint64_t stop = gpu::processor_clock();
+  __nvvm_membar_sys();
+  gpu::sync_threads();
+  asm volatile("" ::"r"(stop));
+  volatile T output = result;
+
+  // Return the time elapsed.
+  return stop - start;
+}
+
+template <typename F, typename T1, typename T2>
+static LIBC_INLINE uint64_t latency(F f, T1 t1, T2 t2) {
+  volatile T1 storage = t1;
+  volatile T2 storage2 = t2;
+  T1 arg = storage;
+  T2 arg2 = storage2;
+  asm volatile("" ::"r"(arg), "r"(arg2));
+
+  gpu::sync_threads();
+  uint64_t start = gpu::processor_clock();
+
+  asm volatile("" ::"r"(arg), "r"(arg2), "llr"(start));
+
+  auto result = f(arg, arg2);
+
+  asm volatile("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :);
+
+  uint64_t stop = gpu::processor_clock();
+  gpu::sync_threads();
+  asm volatile("" ::"r"(stop));
+  volatile auto output = result;
+
+  return stop - start;
+}
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_UTILS_GPU_TIMING_NVPTX
diff --git a/libc/benchmarks/gpu/timing/timing.h b/libc/benchmarks/gpu/timing/timing.h
new file mode 100644
index 0000000000000..c47bb0d9ebb55
--- /dev/null
+++ b/libc/benchmarks/gpu/timing/timing.h
@@ -0,0 +1,22 @@
+//===------------- Implementation of GPU timing utils -----------*- 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 LLVM_LIBC_UTILS_GPU_TIMING_H
+#define LLVM_LIBC_UTILS_GPU_TIMING_H
+
+#include "src/__support/macros/properties/architectures.h"
+
+#if defined(LIBC_TARGET_ARCH_IS_AMDGPU)
+#error "amdgpu not yet supported
+#elif defined(LIBC_TARGET_ARCH_IS_NVPTX)
+#include "nvptx/timing.h"
+#else
+#error "unsupported platform"
+#endif
+
+#endif // LLVM_LIBC_UTILS_GPU_TIMING_H

>From 7b678abef4b157ee216370db7e249f290e9df9b6 Mon Sep 17 00:00:00 2001
From: jameshu15869 <jhudson15869 at gmail.com>
Date: Wed, 15 May 2024 12:47:40 -0400
Subject: [PATCH 2/6] refactor cmake rules

---
 libc/benchmarks/CMakeLists.txt               | 397 +++++++++----------
 libc/benchmarks/gpu/BenchmarkLogger.cpp      |  24 +-
 libc/benchmarks/gpu/CMakeLists.txt           | 162 +-------
 libc/benchmarks/gpu/src/ctype/CMakeLists.txt |  32 +-
 libc/benchmarks/gpu/timing/CMakeLists.txt    |  14 +-
 libc/benchmarks/gpu/timing/timing.h          |   2 +-
 libc/cmake/modules/LLVMLibCTestRules.cmake   |  10 +-
 7 files changed, 259 insertions(+), 382 deletions(-)

diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt
index a802e653a091e..8b51511e3b5cf 100644
--- a/libc/benchmarks/CMakeLists.txt
+++ b/libc/benchmarks/CMakeLists.txt
@@ -1,211 +1,210 @@
-if(NOT LIBC_TARGET_OS_IS_GPU)
-	find_package(Threads)
-
-	set(LLVM_LINK_COMPONENTS
-	  Support
-	  TargetParser
-	  )
-
-	#==============================================================================
-	# Add Unit Testing Support
-	#==============================================================================
-
-	function(add_libc_benchmark_unittest target_name)
-	  if(NOT LLVM_INCLUDE_TESTS)
-	    return()
-	  endif()
-
-	  cmake_parse_arguments(
-	    "LIBC_BENCHMARKS_UNITTEST"
-	    "" # No optional arguments
-	    "SUITE" # Single value arguments
-	    "SRCS;DEPENDS" # Multi-value arguments
-	    ${ARGN}
-	  )
-
-	  add_executable(${target_name}
-	    EXCLUDE_FROM_ALL
-	    ${LIBC_BENCHMARKS_UNITTEST_SRCS}
-	  )
-	  target_link_libraries(${target_name}
-	    PRIVATE
-	    llvm_gtest_main
-	    llvm_gtest
-	    ${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
-	  )
-	  llvm_update_compile_flags(${target_name})
-
-	  add_custom_command(
-	    TARGET ${target_name}
-	    POST_BUILD
-	    COMMAND $<TARGET_FILE:${target_name}>
-	  )
-	  add_dependencies(libc-benchmark-util-tests ${target_name})
-	endfunction()
-
-	#==============================================================================
-	# Build Google Benchmark for libc
-	#==============================================================================
-
-	include(ExternalProject)
-	ExternalProject_Add(google-benchmark-libc
-		EXCLUDE_FROM_ALL ON
-		PREFIX google-benchmark-libc
-		SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
-		INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
-		CMAKE_CACHE_ARGS
-		  -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
-		  -DBENCHMARK_ENABLE_LTO:BOOL=OFF
-		  -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
-		  -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
-		  -DBENCHMARK_FORCE_WERROR:BOOL=OFF
-		  -DBENCHMARK_USE_LIBCXX:BOOL=OFF
-		  -DCMAKE_BUILD_TYPE:STRING=Release
-
-		  -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
-		  -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
-		  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-		  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-		  -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
-		  -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
-
-		  -DBUILD_SHARED_LIBS:BOOL=OFF
-		  -DCMAKE_EXE_LINKER_FLAGS:STRING=-static
-
-		  -DCMAKE_CXX_STANDARD:STRING=14
-		  -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-		)
-
-	add_custom_target(libc-benchmark-util-tests)
-
-	# libc-benchmark
-	add_library(libc-benchmark
-	    STATIC
-	    EXCLUDE_FROM_ALL
-	    LibcBenchmark.cpp
-	    LibcBenchmark.h
-	)
+if(LIBC_TARGET_OS_IS_GPU)
+	add_subdirectory(gpu)
+	return()
+endif()
 
-	target_include_directories(libc-benchmark
-	    PUBLIC ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}
-	)
-	target_link_libraries(libc-benchmark
-	    PUBLIC
-	    benchmark::benchmark
-            LLVMSupport
-	    LLVMTargetParser
-	    Threads::Threads
-	)
-	add_dependencies(libc-benchmark google-benchmark-libc)
-	llvm_update_compile_flags(libc-benchmark)
+find_package(Threads)
 
-	add_libc_benchmark_unittest(libc-benchmark-test
-	    SRCS LibcBenchmarkTest.cpp
-	    DEPENDS libc-benchmark
+set(LLVM_LINK_COMPONENTS
+	Support
+	TargetParser
 	)
 
-	# libc-memory-benchmark
-	add_library(libc-memory-benchmark
-	    STATIC
-	    EXCLUDE_FROM_ALL
-	    LibcMemoryBenchmark.cpp
-	    LibcMemoryBenchmark.h
-	    LibcFunctionPrototypes.h
-	    MemorySizeDistributions.cpp
-	    MemorySizeDistributions.h
-	)
-	target_include_directories(libc-memory-benchmark
-	    PUBLIC
-	    ${CMAKE_CURRENT_SOURCE_DIR}
+#==============================================================================
+# Add Unit Testing Support
+#==============================================================================
+
+function(add_libc_benchmark_unittest target_name)
+	if(NOT LLVM_INCLUDE_TESTS)
+	return()
+	endif()
+
+	cmake_parse_arguments(
+	"LIBC_BENCHMARKS_UNITTEST"
+	"" # No optional arguments
+	"SUITE" # Single value arguments
+	"SRCS;DEPENDS" # Multi-value arguments
+	${ARGN}
 	)
-	target_link_libraries(libc-memory-benchmark
-	    PUBLIC
-	    libc-benchmark
-	)
-	llvm_update_compile_flags(libc-memory-benchmark)
 
-	add_libc_benchmark_unittest(libc-memory-benchmark-test
-	    SRCS LibcMemoryBenchmarkTest.cpp
-	    DEPENDS libc-memory-benchmark
+	add_executable(${target_name}
+	EXCLUDE_FROM_ALL
+	${LIBC_BENCHMARKS_UNITTEST_SRCS}
 	)
-
-	# json
-	add_library(json
-	    STATIC
-	    EXCLUDE_FROM_ALL
-	    JSON.cpp
-	    JSON.h
+	target_link_libraries(${target_name}
+	PRIVATE
+	llvm_gtest_main
+	llvm_gtest
+	${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
 	)
-	target_link_libraries(json PUBLIC libc-memory-benchmark)
-	llvm_update_compile_flags(json)
+	llvm_update_compile_flags(${target_name})
 
-	add_libc_benchmark_unittest(json-test
-	    SRCS JSONTest.cpp
-	    DEPENDS json
+	add_custom_command(
+	TARGET ${target_name}
+	POST_BUILD
+	COMMAND $<TARGET_FILE:${target_name}>
 	)
-
-	#==============================================================================
-	# Benchmarking tool
-	#==============================================================================
-
-	# Benchmark all implementations that can run on the target CPU.
-	function(add_libc_multi_impl_benchmark name)
-	  get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
-	  foreach(fq_config_name IN LISTS fq_implementations)
-	    get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)
-	    cpu_supports(can_run "${required_cpu_features}")
-	    if(can_run)
-		set(benchmark_name ${fq_config_name}_benchmark)
-		add_executable(${benchmark_name}
-		    EXCLUDE_FROM_ALL
-		    LibcMemoryBenchmarkMain.cpp
-		)
-		get_target_property(entrypoint_object_file ${fq_config_name} "OBJECT_FILE_RAW")
-		target_link_libraries(${benchmark_name} PUBLIC json ${entrypoint_object_file})
-		string(TOUPPER ${name} name_upper)
-		target_compile_definitions(${benchmark_name} PRIVATE "-DLIBC_BENCHMARK_FUNCTION_${name_upper}=LIBC_NAMESPACE::${name}" "-DLIBC_BENCHMARK_FUNCTION_NAME=\"${fq_config_name}\"")
-		llvm_update_compile_flags(${benchmark_name})
-	    else()
-	      message(STATUS "Skipping benchmark for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")
-	    endif()
-	  endforeach()
-	endfunction()
-
-	add_libc_multi_impl_benchmark(bcmp)
-	add_libc_multi_impl_benchmark(bzero)
-	add_libc_multi_impl_benchmark(memcmp)
-	add_libc_multi_impl_benchmark(memcpy)
-	add_libc_multi_impl_benchmark(memmove)
-	add_libc_multi_impl_benchmark(memset)
-
-	#==============================================================================
-	# Google Benchmarking tool
-	#==============================================================================
-
-	# This target uses the Google Benchmark facility to report throughput for llvm
-	# libc memory functions compiled for the host machine. This is useful to
-	# continuously monitor the performance of the memory functions.
-	add_executable(libc.benchmarks.memory_functions.opt_host
-	  EXCLUDE_FROM_ALL
-	  LibcMemoryGoogleBenchmarkMain.cpp
-	  LibcDefaultImplementations.cpp
-	)
-	target_link_libraries(libc.benchmarks.memory_functions.opt_host
-	  PRIVATE
-	  libc-memory-benchmark
-	  libc.src.string.memcmp_opt_host.__internal__
-	  libc.src.string.bcmp_opt_host.__internal__
-	  libc.src.string.memcpy_opt_host.__internal__
-	  libc.src.string.memset_opt_host.__internal__
-	  libc.src.string.bzero_opt_host.__internal__
-	  libc.src.string.memmove_opt_host.__internal__
-	  benchmark_main
+	add_dependencies(libc-benchmark-util-tests ${target_name})
+endfunction()
+
+#==============================================================================
+# Build Google Benchmark for libc
+#==============================================================================
+
+include(ExternalProject)
+ExternalProject_Add(google-benchmark-libc
+	EXCLUDE_FROM_ALL ON
+	PREFIX google-benchmark-libc
+	SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
+	INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
+	CMAKE_CACHE_ARGS
+		-DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
+		-DBENCHMARK_ENABLE_LTO:BOOL=OFF
+		-DBENCHMARK_ENABLE_TESTING:BOOL=OFF
+		-DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
+		-DBENCHMARK_FORCE_WERROR:BOOL=OFF
+		-DBENCHMARK_USE_LIBCXX:BOOL=OFF
+		-DCMAKE_BUILD_TYPE:STRING=Release
+
+		-DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
+		-DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
+		-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+		-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+		-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+		-DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
+
+		-DBUILD_SHARED_LIBS:BOOL=OFF
+		-DCMAKE_EXE_LINKER_FLAGS:STRING=-static
+
+		-DCMAKE_CXX_STANDARD:STRING=14
+		-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
 	)
-	llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host)
-
-	add_subdirectory(automemcpy)
-endif()
 
-if(LIBC_TARGET_OS_IS_GPU)
-	add_subdirectory(gpu)
-endif()
+add_custom_target(libc-benchmark-util-tests)
+
+# libc-benchmark
+add_library(libc-benchmark
+	STATIC
+	EXCLUDE_FROM_ALL
+	LibcBenchmark.cpp
+	LibcBenchmark.h
+)
+
+target_include_directories(libc-benchmark
+	PUBLIC ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}
+)
+target_link_libraries(libc-benchmark
+	PUBLIC
+	benchmark::benchmark
+		LLVMSupport
+	LLVMTargetParser
+	Threads::Threads
+)
+add_dependencies(libc-benchmark google-benchmark-libc)
+llvm_update_compile_flags(libc-benchmark)
+
+add_libc_benchmark_unittest(libc-benchmark-test
+	SRCS LibcBenchmarkTest.cpp
+	DEPENDS libc-benchmark
+)
+
+# libc-memory-benchmark
+add_library(libc-memory-benchmark
+	STATIC
+	EXCLUDE_FROM_ALL
+	LibcMemoryBenchmark.cpp
+	LibcMemoryBenchmark.h
+	LibcFunctionPrototypes.h
+	MemorySizeDistributions.cpp
+	MemorySizeDistributions.h
+)
+target_include_directories(libc-memory-benchmark
+	PUBLIC
+	${CMAKE_CURRENT_SOURCE_DIR}
+)
+target_link_libraries(libc-memory-benchmark
+	PUBLIC
+	libc-benchmark
+)
+llvm_update_compile_flags(libc-memory-benchmark)
+
+add_libc_benchmark_unittest(libc-memory-benchmark-test
+	SRCS LibcMemoryBenchmarkTest.cpp
+	DEPENDS libc-memory-benchmark
+)
+
+# json
+add_library(json
+	STATIC
+	EXCLUDE_FROM_ALL
+	JSON.cpp
+	JSON.h
+)
+target_link_libraries(json PUBLIC libc-memory-benchmark)
+llvm_update_compile_flags(json)
+
+add_libc_benchmark_unittest(json-test
+	SRCS JSONTest.cpp
+	DEPENDS json
+)
+
+#==============================================================================
+# Benchmarking tool
+#==============================================================================
+
+# Benchmark all implementations that can run on the target CPU.
+function(add_libc_multi_impl_benchmark name)
+	get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
+	foreach(fq_config_name IN LISTS fq_implementations)
+	get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)
+	cpu_supports(can_run "${required_cpu_features}")
+	if(can_run)
+	set(benchmark_name ${fq_config_name}_benchmark)
+	add_executable(${benchmark_name}
+		EXCLUDE_FROM_ALL
+		LibcMemoryBenchmarkMain.cpp
+	)
+	get_target_property(entrypoint_object_file ${fq_config_name} "OBJECT_FILE_RAW")
+	target_link_libraries(${benchmark_name} PUBLIC json ${entrypoint_object_file})
+	string(TOUPPER ${name} name_upper)
+	target_compile_definitions(${benchmark_name} PRIVATE "-DLIBC_BENCHMARK_FUNCTION_${name_upper}=LIBC_NAMESPACE::${name}" "-DLIBC_BENCHMARK_FUNCTION_NAME=\"${fq_config_name}\"")
+	llvm_update_compile_flags(${benchmark_name})
+	else()
+		message(STATUS "Skipping benchmark for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")
+	endif()
+	endforeach()
+endfunction()
+
+add_libc_multi_impl_benchmark(bcmp)
+add_libc_multi_impl_benchmark(bzero)
+add_libc_multi_impl_benchmark(memcmp)
+add_libc_multi_impl_benchmark(memcpy)
+add_libc_multi_impl_benchmark(memmove)
+add_libc_multi_impl_benchmark(memset)
+
+#==============================================================================
+# Google Benchmarking tool
+#==============================================================================
+
+# This target uses the Google Benchmark facility to report throughput for llvm
+# libc memory functions compiled for the host machine. This is useful to
+# continuously monitor the performance of the memory functions.
+add_executable(libc.benchmarks.memory_functions.opt_host
+	EXCLUDE_FROM_ALL
+	LibcMemoryGoogleBenchmarkMain.cpp
+	LibcDefaultImplementations.cpp
+)
+target_link_libraries(libc.benchmarks.memory_functions.opt_host
+	PRIVATE
+	libc-memory-benchmark
+	libc.src.string.memcmp_opt_host.__internal__
+	libc.src.string.bcmp_opt_host.__internal__
+	libc.src.string.memcpy_opt_host.__internal__
+	libc.src.string.memset_opt_host.__internal__
+	libc.src.string.bzero_opt_host.__internal__
+	libc.src.string.memmove_opt_host.__internal__
+	benchmark_main
+)
+llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host)
+
+add_subdirectory(automemcpy)
diff --git a/libc/benchmarks/gpu/BenchmarkLogger.cpp b/libc/benchmarks/gpu/BenchmarkLogger.cpp
index 94a0d897c9585..4f70d23a1e95e 100644
--- a/libc/benchmarks/gpu/BenchmarkLogger.cpp
+++ b/libc/benchmarks/gpu/BenchmarkLogger.cpp
@@ -13,18 +13,21 @@ namespace libc_gpu_benchmarks {
 
 // cpp::string_view specialization
 template <>
-BenchmarkLogger &BenchmarkLogger::operator<< <cpp::string_view>(cpp::string_view str) {
+BenchmarkLogger &
+    BenchmarkLogger::operator<< <cpp::string_view>(cpp::string_view str) {
   LIBC_NAMESPACE::write_to_stderr(str);
   return *this;
 }
 
 // cpp::string specialization
-template <> BenchmarkLogger &BenchmarkLogger::operator<< <cpp::string>(cpp::string str) {
+template <>
+BenchmarkLogger &BenchmarkLogger::operator<< <cpp::string>(cpp::string str) {
   return *this << static_cast<cpp::string_view>(str);
 }
 
 // const char* specialization
-template <> BenchmarkLogger &BenchmarkLogger::operator<< <const char *>(const char *str) {
+template <>
+BenchmarkLogger &BenchmarkLogger::operator<< <const char *>(const char *str) {
   return *this << cpp::string_view(str);
 }
 
@@ -66,15 +69,20 @@ template BenchmarkLogger &BenchmarkLogger::operator<< <short>(short);
 template BenchmarkLogger &BenchmarkLogger::operator<< <int>(int);
 template BenchmarkLogger &BenchmarkLogger::operator<< <long>(long);
 template BenchmarkLogger &BenchmarkLogger::operator<< <long long>(long long);
-template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned char>(unsigned char);
-template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned short>(unsigned short);
-template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned int>(unsigned int);
-template BenchmarkLogger &BenchmarkLogger::operator<< <unsigned long>(unsigned long);
+template BenchmarkLogger &
+    BenchmarkLogger::operator<< <unsigned char>(unsigned char);
+template BenchmarkLogger &
+    BenchmarkLogger::operator<< <unsigned short>(unsigned short);
+template BenchmarkLogger &
+    BenchmarkLogger::operator<< <unsigned int>(unsigned int);
+template BenchmarkLogger &
+    BenchmarkLogger::operator<< <unsigned long>(unsigned long);
 template BenchmarkLogger &
     BenchmarkLogger::operator<< <unsigned long long>(unsigned long long);
 
 #ifdef LIBC_TYPES_HAS_INT128
-template BenchmarkLogger &BenchmarkLogger::operator<< <__uint128_t>(__uint128_t);
+template BenchmarkLogger &
+    BenchmarkLogger::operator<< <__uint128_t>(__uint128_t);
 #endif // LIBC_TYPES_HAS_INT128
 template BenchmarkLogger &BenchmarkLogger::operator<< <UInt<128>>(UInt<128>);
 template BenchmarkLogger &BenchmarkLogger::operator<< <UInt<192>>(UInt<192>);
diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt
index a18be27e33573..5dafe66bbd738 100644
--- a/libc/benchmarks/gpu/CMakeLists.txt
+++ b/libc/benchmarks/gpu/CMakeLists.txt
@@ -2,161 +2,25 @@ add_subdirectory(timing)
 
 add_custom_target(gpu-benchmark)
 
-function (add_gpu_benchmark test_name)
-  if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)
-    message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")
-    return()
-  endif()
-
+function(add_benchmark benchmark_name)
   cmake_parse_arguments(
-    "GPU_BENCHMARK"
-    "" # No optional arguments
-    "SUITE" # Single value arguments
-    "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments
+    "BENCHMARK"
+    "LINK_LIBRARIES" # Optional arguments
+    "" # Single value arguments
+    "" # Multi-value arguments
     ${ARGN}
   )
-
-  if(NOT GPU_BENCHMARK_SUITE)
-    message(FATAL_ERROR "SUITE not specified for ${fq_target_name}")
-  endif()
-  if(NOT GPU_BENCHMARK_SRCS)
-    message(FATAL_ERROR "The SRCS list for add_gpu_benchmark is missing.")
-  endif()
-
-  get_fq_target_name(${test_name} fq_target_name)
-  get_fq_target_name(${test_name}.libc fq_libc_target_name) # Stores the compiled libc + infrastructure archive to link in
-  get_fq_deps_list(fq_deps_list ${GPU_BENCHMARK_DEPENDS})
-  list(APPEND fq_deps_list
-      # Hermetic tests use the platform's startup object. So, their deps also
-      # have to be collected.
-      libc.startup.${LIBC_TARGET_OS}.crt1
-      # We always add the memory functions objects. This is because the
-      # compiler's codegen can emit calls to the C memory functions.
-      libc.src.string.bcmp
-      libc.src.string.bzero
-      libc.src.string.memcmp
-      libc.src.string.memcpy
-      libc.src.string.memmove
-      libc.src.string.memset
-      libc.src.__support.StringUtil.error_to_string
-  )
-
-  list(REMOVE_DUPLICATES fq_deps_list)
-
-  # TODO: Instead of gathering internal object files from entrypoints,
-  # collect the object files with public names of entrypoints.
-  get_object_files_for_test(
-      link_object_files skipped_entrypoints_list ${fq_deps_list})
-  if(skipped_entrypoints_list)
-    if(LIBC_CMAKE_VERBOSE_LOGGING)
-      set(msg "Skipping hermetic test ${fq_target_name} as it has missing deps: "
-              "${skipped_entrypoints_list}.")
-    endif()
-    return()
-  endif()
-  list(REMOVE_DUPLICATES link_object_files)
-
-  # Make a library of all deps
-  add_library(
-    ${fq_target_name}.__libc__
-    STATIC
-    EXCLUDE_FROM_ALL
-    ${link_object_files}
-  )
-  set_target_properties(${fq_target_name}.__libc__
-      PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-  set_target_properties(${fq_target_name}.__libc__
-      PROPERTIES ARCHIVE_OUTPUT_NAME ${fq_target_name}.libc)
-
-  set(fq_build_target_name ${fq_target_name}.__build__)
-  add_executable(
-    ${fq_build_target_name}
-    EXCLUDE_FROM_ALL
-    $<$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>:${link_object_files}>
-    ${GPU_BENCHMARK_SRCS}
-    ${GPU_BENCHMARK_HDRS}
-  )
-  set_target_properties(${fq_build_target_name}
-    PROPERTIES
-      RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-  )
-
-  _get_hermetic_test_compile_options(compile_options "${GPU_BENCHMARK_COMPILE_OPTIONS}")
-  target_include_directories(${fq_build_target_name} SYSTEM PRIVATE ${LIBC_INCLUDE_DIR})
-  target_include_directories(${fq_build_target_name} PRIVATE ${LIBC_SOURCE_DIR})
-  _get_hermetic_test_compile_options(compile_options "${GPU_BENCHMARK_COMPILE_OPTIONS}")
-  target_compile_options(${fq_build_target_name} PRIVATE ${compile_options}) 
-
-  set(link_libraries "")
-  foreach(lib in LISTS GPU_BENCHMARK_LINK_LIBRARIES)
-    if(TARGET ${lib}.hermetic)
-      list(APPEND link_libraries ${lib}.hermetic)
-    else()
-      list(APPEND link_libraries ${lib})
-    endif()
-  endforeach()
-
-  if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
-    target_link_options(${fq_build_target_name} PRIVATE
-      ${LIBC_COMPILE_OPTIONS_DEFAULT}
-      -mcpu=${LIBC_GPU_TARGET_ARCHITECTURE} -flto -Wno-multi-gpu
-      "-Wl,-mllvm,-amdgpu-lower-global-ctor-dtor=0" -nostdlib -static
-      "-Wl,-mllvm,-amdhsa-code-object-version=${LIBC_GPU_CODE_OBJECT_VERSION}")
-  elseif(LIBC_TARGET_ARCHITECTURE_IS_NVPTX)
-    # We need to use the internal object versions for NVPTX.
-    set(internal_suffix ".__internal__")
-    target_link_options(${fq_build_target_name} PRIVATE
-      ${LIBC_COMPILE_OPTIONS_DEFAULT} -Wno-multi-gpu
-      "-Wl,--suppress-stack-size-warning"
-      -march=${LIBC_GPU_TARGET_ARCHITECTURE} -nostdlib -static
-      "--cuda-path=${LIBC_CUDA_ROOT}")
-  elseif(LIBC_CC_SUPPORTS_NOSTDLIBPP)
-    target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib++ -static)
-  else()
-    # Older version of gcc does not support `nostdlib++` flag.  We use
-    # `nostdlib` and link against libgcc_s, which cannot be linked statically.
-    target_link_options(${fq_build_target_name} PRIVATE -nolibc -nostartfiles -nostdlib)
-    list(APPEND link_libraries ${LIBGCC_S_LOCATION})
-  endif()
-
-  # link libraries for the BUILD target (i.e. to compile the test)
-  target_link_libraries(
-    ${fq_build_target_name}
-    PRIVATE
-      libc.startup.${LIBC_TARGET_OS}.crt1${internal_suffix}
-      ${link_libraries}
-      # LibcTest.hermetic
+  add_libc_hermetic_test(
+    ${benchmark_name}
+    IS_BENCHMARK
+    LINK_LIBRARIES
       LibcGpuBenchmark.hermetic
-      # LibcHermeticTestSupport.hermetic
-      LibcHermeticTestSupport.hermetic
-      # The NVIDIA 'nvlink' linker does not currently support static libraries.
-      $<$<NOT:$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>>:${fq_target_name}.__libc__>)
-
-  add_dependencies(${fq_build_target_name}
-    LibcGpuBenchmark.hermetic
-  ${fq_deps_list})
-
-  # Tests on the GPU require an external loader utility to launch the kernel.
-  if(TARGET libc.utils.gpu.loader)
-    add_dependencies(${fq_build_target_name} libc.utils.gpu.loader)
-    get_target_property(gpu_loader_exe libc.utils.gpu.loader "EXECUTABLE")
-  endif()
-
-  set(test_cmd ${GPU_BENCHMARK_ENV}
-      $<$<BOOL:${LIBC_TARGET_OS_IS_GPU}>:${gpu_loader_exe}> ${CMAKE_CROSSCOMPILING_EMULATOR} ${GPU_BENCHMARK_LOADER_ARGS}
-      $<TARGET_FILE:${fq_build_target_name}> ${GPU_BENCHMARK_ARGS})
-  add_custom_target(
-    ${fq_target_name}
-    COMMAND ${test_cmd}
-    COMMAND_EXPAND_LISTS
-    COMMENT "Running GPU benchmark ${fq_target_name}"
+      ${BENCHMARK_LINK_LIBRARIES}
+    ${BENCHMARK_UNPARSED_ARGUMENTS}
   )
-
-  # Make this benchmark part of its suite
-  add_dependencies(${GPU_BENCHMARK_SUITE} ${fq_target_name})
-  # Remember to make this benchmark part of the umbrella command
+  get_fq_target_name(${benchmark_name} fq_target_name)
   add_dependencies(gpu-benchmark ${fq_target_name})
-endfunction(add_gpu_benchmark)
+endfunction(add_benchmark)
 
 add_unittest_framework_library(
   LibcGpuBenchmark
diff --git a/libc/benchmarks/gpu/src/ctype/CMakeLists.txt b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
index ab2f6cdf0c7fd..8d448b8ced955 100644
--- a/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
+++ b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
@@ -1,21 +1,21 @@
 add_custom_target(libc-gpu-ctype-benchmarks)
 
-add_gpu_benchmark(
-    isalnum_benchmark
-    SUITE
-        libc-gpu-ctype-benchmarks
-    SRCS
-        isalnum_benchmark.cpp
-    DEPENDS
-        libc.src.ctype.isalnum
+add_benchmark(
+	isalnum_benchmark
+	SUITE
+		libc-gpu-ctype-benchmarks
+	SRCS
+		isalnum_benchmark.cpp
+	DEPENDS
+		libc.src.ctype.isalnum
 )
 
-add_gpu_benchmark(
-    isalpha_benchmark
-    SUITE
-        libc-gpu-ctype-benchmarks
-    SRCS
-        isalpha_benchmark.cpp
-    DEPENDS
-        libc.src.ctype.isalpha
+add_benchmark(
+	isalpha_benchmark
+	SUITE
+		libc-gpu-ctype-benchmarks
+	SRCS
+		isalpha_benchmark.cpp
+	DEPENDS
+		libc.src.ctype.isalpha
 )
diff --git a/libc/benchmarks/gpu/timing/CMakeLists.txt b/libc/benchmarks/gpu/timing/CMakeLists.txt
index 0e6a5a6b47968..8bbc7e33f122a 100644
--- a/libc/benchmarks/gpu/timing/CMakeLists.txt
+++ b/libc/benchmarks/gpu/timing/CMakeLists.txt
@@ -1,12 +1,12 @@
 foreach(target nvptx)
-    add_subdirectory(${target})
-    list(APPEND target_gpu_timing libc.benchmarks.gpu.timing.${target}.${target}_timing)
+  add_subdirectory(${target})
+  list(APPEND target_gpu_timing libc.benchmarks.gpu.timing.${target}.${target}_timing)
 endforeach()
 
 add_header_library(
-    timing
-    HDRS
-        timing.h
-    DEPENDS
-        ${target_gpu_timing}
+  timing
+  HDRS
+    timing.h
+  DEPENDS
+    ${target_gpu_timing}
 )
diff --git a/libc/benchmarks/gpu/timing/timing.h b/libc/benchmarks/gpu/timing/timing.h
index c47bb0d9ebb55..180ea77954ae5 100644
--- a/libc/benchmarks/gpu/timing/timing.h
+++ b/libc/benchmarks/gpu/timing/timing.h
@@ -12,7 +12,7 @@
 #include "src/__support/macros/properties/architectures.h"
 
 #if defined(LIBC_TARGET_ARCH_IS_AMDGPU)
-#error "amdgpu not yet supported
+#error "amdgpu not yet supported"
 #elif defined(LIBC_TARGET_ARCH_IS_NVPTX)
 #include "nvptx/timing.h"
 #else
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index eb6be91b55e26..3d4f18a1291a5 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -550,7 +550,7 @@ function(add_libc_hermetic_test test_name)
   endif()
   cmake_parse_arguments(
     "HERMETIC_TEST"
-    "" # No optional arguments
+    "IS_BENCHMARK" # Optional arguments
     "SUITE" # Single value arguments
     "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments
     ${ARGN}
@@ -651,6 +651,13 @@ function(add_libc_hermetic_test test_name)
     endif()
   endforeach()
 
+  # Benchmarks requires a separate library with a different `main` function
+  if(HERMETIC_TEST_IS_BENCHMARK)
+    list(APPEND link_libraries LibcGpuBenchmark.hermetic)
+  else()
+    list(APPEND link_libraries LibcTest.hermetic)
+  endif()
+
   if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
     target_link_options(${fq_build_target_name} PRIVATE
       ${LIBC_COMPILE_OPTIONS_DEFAULT}
@@ -678,7 +685,6 @@ function(add_libc_hermetic_test test_name)
     PRIVATE
       libc.startup.${LIBC_TARGET_OS}.crt1${internal_suffix}
       ${link_libraries}
-      LibcTest.hermetic
       LibcHermeticTestSupport.hermetic
       # The NVIDIA 'nvlink' linker does not currently support static libraries.
       $<$<NOT:$<BOOL:${LIBC_TARGET_ARCHITECTURE_IS_NVPTX}>>:${fq_target_name}.__libc__>)

>From 47057fa766411c683604418bc7aeef1cdfa5a807 Mon Sep 17 00:00:00 2001
From: jameshu15869 <jhudson15869 at gmail.com>
Date: Thu, 16 May 2024 13:08:37 -0400
Subject: [PATCH 3/6] fix code style

---
 libc/benchmarks/gpu/CMakeLists.txt           |   1 +
 libc/benchmarks/gpu/LibcGpuBenchmark.cpp     |  87 ++++++++-------
 libc/benchmarks/gpu/LibcGpuBenchmark.h       | 105 +++++++++----------
 libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp |   2 +-
 4 files changed, 97 insertions(+), 98 deletions(-)

diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt
index 5dafe66bbd738..db2953f6fcf23 100644
--- a/libc/benchmarks/gpu/CMakeLists.txt
+++ b/libc/benchmarks/gpu/CMakeLists.txt
@@ -37,6 +37,7 @@ add_unittest_framework_library(
     libc.src.__support.CPP.string
     libc.src.__support.CPP.string_view
     libc.src.__support.CPP.type_traits
+    libc.src.__support.CPP.functional
     libc.src.__support.fixed_point.fx_rep
     libc.src.__support.macros.properties.types
     libc.src.__support.OSUtil.osutil
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
index d37f5a0a53a70..087b59689d90b 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
@@ -3,67 +3,66 @@
 namespace LIBC_NAMESPACE {
 namespace libc_gpu_benchmarks {
 
-Benchmark *Benchmark::Start = nullptr;
-Benchmark *Benchmark::End = nullptr;
+Benchmark *Benchmark::start = nullptr;
+Benchmark *Benchmark::end = nullptr;
 
-void Benchmark::addBenchmark(Benchmark *B) {
-  if (End == nullptr) {
-    Start = B;
-    End = B;
+void Benchmark::add_benchmark(Benchmark *benchmark) {
+  if (end == nullptr) {
+    start = benchmark;
+    end = benchmark;
     return;
   }
-
-  End->Next = B;
-  End = B;
+  end->next = benchmark;
+  end = benchmark;
 }
 
-int Benchmark::runBenchmarks() {
-  for (Benchmark *B = Start; B != nullptr; B = B->Next) {
-    B->Run();
-  }
-
+int Benchmark::run_benchmarks() {
+  for (Benchmark *b = start; b != nullptr; b = b->next)
+    b->run();
   return 0;
 }
 
-BenchmarkResult benchmark(const BenchmarkOptions &Options,
-                          uint64_t (*WrapperFunc)()) {
-  BenchmarkResult Result;
-  RuntimeEstimationProgression REP;
-  size_t TotalIterations = 0;
-  size_t Iterations = Options.InitialIterations;
-  if (Iterations < (uint32_t)1) {
-    Iterations = 1;
-  }
-  size_t Samples = 0;
-  uint64_t BestGuess = 0;
-  uint64_t TotalCycles = 0;
+BenchmarkResult benchmark(const BenchmarkOptions &options,
+                          cpp::function<uint64_t(void)> wrapper_func) {
+  BenchmarkResult result;
+  RuntimeEstimationProgression rep;
+  size_t total_iterations = 0;
+  size_t iterations = options.initial_iterations;
+  if (iterations < (uint32_t)1)
+    iterations = 1;
+
+  size_t samples = 0;
+  uint64_t best_guess = 0;
+  uint64_t total_cycles = 0;
   for (;;) {
-    uint64_t SampleCycles = 0;
-    for (uint32_t i = 0; i < Iterations; i++) {
-      auto overhead = LIBC_NAMESPACE::overhead();
-      uint64_t result = WrapperFunc() - overhead;
-      SampleCycles += result;
+    uint64_t sample_cycles = 0;
+    uint64_t overhead = LIBC_NAMESPACE::overhead();
+    for (uint32_t i = 0; i < iterations; i++) {
+      uint64_t result = wrapper_func() - overhead;
+      sample_cycles += result;
     }
 
-    Samples++;
-    TotalCycles += SampleCycles;
-    TotalIterations += Iterations;
-    const double ChangeRatio =
-        REP.ComputeImprovement({Iterations, SampleCycles});
-    BestGuess = REP.CurrentEstimation;
+    samples++;
+    total_cycles += sample_cycles;
+    total_iterations += iterations;
+    const double change_ratio =
+        rep.compute_improvement({iterations, sample_cycles});
+    best_guess = rep.current_estimation;
 
-    if (Samples >= Options.MaxSamples || Iterations >= Options.MaxIterations) {
+    if (samples >= options.max_samples ||
+        iterations >= options.max_iterations) {
       break;
-    } else if (Samples >= Options.MinSamples && ChangeRatio < Options.Epsilon) {
+    } else if (samples >= options.min_samples &&
+               change_ratio < options.epsilon) {
       break;
     }
 
-    Iterations *= Options.ScalingFactor;
+    iterations *= options.scaling_factor;
   }
-  Result.Cycles = BestGuess;
-  Result.Samples = Samples;
-  Result.TotalIterations = TotalIterations;
-  return Result;
+  result.cycles = best_guess;
+  result.samples = samples;
+  result.total_iterations = total_iterations;
+  return result;
 };
 
 } // namespace libc_gpu_benchmarks
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.h b/libc/benchmarks/gpu/LibcGpuBenchmark.h
index ccbbe3629dbda..3d762631f2d96 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmark.h
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.h
@@ -1,9 +1,10 @@
 #ifndef LLVM_LIBC_BENCHMARKS_LIBC_GPU_BENCHMARK_H
 #define LLVM_LIBC_BENCHMARKS_LIBC_GPU_BENCHMARK_H
 
-#include "benchmarks/gpu/timing/timing.h"
-
 #include "benchmarks/gpu/BenchmarkLogger.h"
+#include "benchmarks/gpu/timing/timing.h"
+#include "src/__support/CPP/functional.h"
+#include "src/__support/CPP/string_view.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -13,104 +14,102 @@ namespace LIBC_NAMESPACE {
 namespace libc_gpu_benchmarks {
 
 struct BenchmarkOptions {
-  uint32_t InitialIterations = 1;
-  uint32_t MaxIterations = 10000000;
-  uint32_t MinSamples = 4;
-  uint32_t MaxSamples = 1000;
-  double Epsilon = 0.01;
-  double ScalingFactor = 1.4;
+  uint32_t initial_iterations = 1;
+  uint32_t max_iterations = 10000000;
+  uint32_t min_samples = 4;
+  uint32_t max_samples = 1000;
+  double epsilon = 0.01;
+  double scaling_factor = 1.4;
 };
 
 struct Measurement {
-  size_t Iterations = 0;
-  uint64_t ElapsedCycles = 0;
+  size_t iterations = 0;
+  uint64_t elapsed_cycles = 0;
 };
 
 class RefinableRuntimeEstimation {
-  uint64_t TotalCycles = 0;
-  size_t TotalIterations = 0;
+  uint64_t total_cycles = 0;
+  size_t total_iterations = 0;
 
 public:
-  uint64_t Update(const Measurement &M) {
-    TotalCycles += M.ElapsedCycles;
-    TotalIterations += M.Iterations;
-    return TotalCycles / TotalIterations;
+  uint64_t update(const Measurement &M) {
+    total_cycles += M.elapsed_cycles;
+    total_iterations += M.iterations;
+    return total_cycles / total_iterations;
   }
 };
 
 // Tracks the progression of the runtime estimation
 class RuntimeEstimationProgression {
-  RefinableRuntimeEstimation RRE;
+  RefinableRuntimeEstimation rre;
 
 public:
-  uint64_t CurrentEstimation = 0;
+  uint64_t current_estimation = 0;
 
-  double ComputeImprovement(const Measurement &M) {
-    const uint64_t NewEstimation = RRE.Update(M);
-    double Ratio = ((double)CurrentEstimation / NewEstimation) - 1.0;
+  double compute_improvement(const Measurement &M) {
+    const uint64_t new_estimation = rre.update(M);
+    double ratio = ((double)current_estimation / new_estimation) - 1.0;
 
     // Get absolute value
-    if (Ratio < 0) {
-      Ratio *= -1;
-    }
+    if (ratio < 0)
+      ratio *= -1;
 
-    CurrentEstimation = NewEstimation;
-    return Ratio;
+    current_estimation = new_estimation;
+    return ratio;
   }
 };
 
 struct BenchmarkResult {
-  uint64_t Cycles = 0;
-  size_t Samples = 0;
-  size_t TotalIterations = 0;
+  uint64_t cycles = 0;
+  size_t samples = 0;
+  size_t total_iterations = 0;
 };
 
-BenchmarkResult benchmark(const BenchmarkOptions &Options,
-                          uint64_t (*WrapperFunc)());
+BenchmarkResult benchmark(const BenchmarkOptions &options,
+                          cpp::function<uint64_t(void)> wrapper_func);
 
 class Benchmark {
-  Benchmark *Next = nullptr;
+  Benchmark *next = nullptr;
 
 public:
   virtual ~Benchmark() {}
-  virtual void SetUp() {}
-  virtual void TearDown() {}
+  virtual void set_up() {}
+  virtual void tear_down() {}
 
-  static int runBenchmarks();
+  static int run_benchmarks();
 
 protected:
-  static void addBenchmark(Benchmark *);
+  static void add_benchmark(Benchmark *);
 
 private:
-  virtual void Run() = 0;
-  virtual const char *getName() const = 0;
+  virtual void run() = 0;
+  virtual const cpp::string_view get_name() const = 0;
 
-  static Benchmark *Start;
-  static Benchmark *End;
+  static Benchmark *start;
+  static Benchmark *end;
 };
 
 class WrapperBenchmark : public Benchmark {
-  using BenchmarkWrapperFunction = uint64_t (*)();
-  BenchmarkWrapperFunction Func;
-  const char *Name;
+  const cpp::function<uint64_t(void)> func;
+  const cpp::string_view name;
 
 public:
-  WrapperBenchmark(BenchmarkWrapperFunction Func, char const *Name)
-      : Func(Func), Name(Name) {
-    addBenchmark(this);
+  WrapperBenchmark(cpp::function<uint64_t(void)> func, char const *name)
+      : func(func), name(name) {
+    add_benchmark(this);
   }
 
 private:
-  void Run() override {
-    BenchmarkOptions Options;
-    auto result = benchmark(Options, Func);
+  void run() override {
+    BenchmarkOptions options;
+    auto result = benchmark(options, func);
     constexpr auto GREEN = "\033[32m";
     constexpr auto RESET = "\033[0m";
-    blog << GREEN << "[ RUN      ] " << RESET << Name << '\n';
-    blog << GREEN << "[       OK ] " << RESET << Name << ": " << result.Cycles
-         << " cycles, " << result.TotalIterations << " iterations\n";
+    blog << GREEN << "[ RUN      ] " << RESET << name << '\n';
+    blog << GREEN << "[       OK ] " << RESET << name << ": " << result.cycles
+         << " cycles, " << result.total_iterations << " iterations\n";
   }
-  const char *getName() const override { return Name; }
+  const cpp::string_view get_name() const override { return name; }
 };
 } // namespace libc_gpu_benchmarks
 } // namespace LIBC_NAMESPACE
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp b/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp
index c971b00cc9a1b..510fd13210494 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp
+++ b/libc/benchmarks/gpu/LibcGpuBenchmarkMain.cpp
@@ -1,6 +1,6 @@
 #include "LibcGpuBenchmark.h"
 
 extern "C" int main(int argc, char **argv, char **envp) {
-  LIBC_NAMESPACE::libc_gpu_benchmarks::Benchmark::runBenchmarks();
+  LIBC_NAMESPACE::libc_gpu_benchmarks::Benchmark::run_benchmarks();
   return 0;
 }

>From aec5e525f6fc3ad59f4b25c91781ab10e07cf7ae Mon Sep 17 00:00:00 2001
From: jameshu15869 <jhudson15869 at gmail.com>
Date: Fri, 17 May 2024 16:22:23 -0400
Subject: [PATCH 4/6] measure walltime, standard deviation, min, and max

---
 libc/benchmarks/gpu/CMakeLists.txt            |  7 +++++
 libc/benchmarks/gpu/LibcGpuBenchmark.cpp      | 31 ++++++++++++++++---
 libc/benchmarks/gpu/LibcGpuBenchmark.h        | 12 ++++++-
 .../gpu/src/ctype/isalnum_benchmark.cpp       | 13 --------
 libc/benchmarks/gpu/timing/nvptx/timing.h     | 13 +++-----
 5 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt
index db2953f6fcf23..b9ca85393cc2e 100644
--- a/libc/benchmarks/gpu/CMakeLists.txt
+++ b/libc/benchmarks/gpu/CMakeLists.txt
@@ -10,6 +10,9 @@ function(add_benchmark benchmark_name)
     "" # Multi-value arguments
     ${ARGN}
   )
+  if(NOT libc.src.time.clock IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS)
+    message(FATAL_ERROR "target does not support clock")
+  endif()
   add_libc_hermetic_test(
     ${benchmark_name}
     IS_BENCHMARK
@@ -38,10 +41,14 @@ add_unittest_framework_library(
     libc.src.__support.CPP.string_view
     libc.src.__support.CPP.type_traits
     libc.src.__support.CPP.functional
+    libc.src.__support.CPP.limits
+    libc.src.__support.CPP.algorithm
     libc.src.__support.fixed_point.fx_rep
     libc.src.__support.macros.properties.types
     libc.src.__support.OSUtil.osutil
     libc.src.__support.uint128
+    libc.src.___support.FPUtil.sqrt
+    libc.src.time.clock
     libc.benchmarks.gpu.timing.timing
 )
 
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
index 087b59689d90b..3ecff18884b34 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
@@ -1,4 +1,7 @@
 #include "LibcGpuBenchmark.h"
+#include "src/__support/CPP/algorithm.h"
+#include "src/__support/FPUtil/sqrt.h"
+#include "src/time/gpu/time_utils.h"
 
 namespace LIBC_NAMESPACE {
 namespace libc_gpu_benchmarks {
@@ -32,27 +35,42 @@ BenchmarkResult benchmark(const BenchmarkOptions &options,
     iterations = 1;
 
   size_t samples = 0;
+  uint64_t total_time = 0;
   uint64_t best_guess = 0;
   uint64_t total_cycles = 0;
+  uint64_t cycles_2 = 0;
+  uint64_t min = UINT_MAX;
+  uint64_t max = 0;
   for (;;) {
     uint64_t sample_cycles = 0;
     uint64_t overhead = LIBC_NAMESPACE::overhead();
+    const clock_t start = (double)clock();
     for (uint32_t i = 0; i < iterations; i++) {
-      uint64_t result = wrapper_func() - overhead;
+      auto wrapper_intermediate = wrapper_func();
+      uint64_t result = wrapper_intermediate - overhead;
+      max = cpp::max(max, result);
+      min = cpp::min(min, result);
       sample_cycles += result;
     }
-
+    const clock_t end = clock();
+    const clock_t duration_ns =
+        ((end - start) * 1000 * 1000 * 1000) / CLOCKS_PER_SEC;
+    total_time += duration_ns;
     samples++;
     total_cycles += sample_cycles;
+    cycles_2 += sample_cycles * sample_cycles;
+
     total_iterations += iterations;
     const double change_ratio =
         rep.compute_improvement({iterations, sample_cycles});
     best_guess = rep.current_estimation;
 
     if (samples >= options.max_samples ||
-        iterations >= options.max_iterations) {
+        iterations >= options.max_iterations ||
+        total_time >= options.max_duration) {
       break;
-    } else if (samples >= options.min_samples &&
+    } else if (total_time >= options.min_duration &&
+               samples >= options.min_samples &&
                change_ratio < options.epsilon) {
       break;
     }
@@ -60,8 +78,13 @@ BenchmarkResult benchmark(const BenchmarkOptions &options,
     iterations *= options.scaling_factor;
   }
   result.cycles = best_guess;
+  result.standard_deviation = fputil::sqrt((double)cycles_2 / total_iterations -
+                                           (best_guess * best_guess));
+  result.min = min;
+  result.max = max;
   result.samples = samples;
   result.total_iterations = total_iterations;
+  result.total_time = total_time;
   return result;
 };
 
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.h b/libc/benchmarks/gpu/LibcGpuBenchmark.h
index 3d762631f2d96..798ae06086b1a 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmark.h
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.h
@@ -4,7 +4,9 @@
 #include "benchmarks/gpu/BenchmarkLogger.h"
 #include "benchmarks/gpu/timing/timing.h"
 #include "src/__support/CPP/functional.h"
+#include "src/__support/CPP/limits.h"
 #include "src/__support/CPP/string_view.h"
+#include "src/time/clock.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -18,6 +20,8 @@ struct BenchmarkOptions {
   uint32_t max_iterations = 10000000;
   uint32_t min_samples = 4;
   uint32_t max_samples = 1000;
+  uint64_t min_duration = 0;                  // in nanoseconds (ns)
+  uint64_t max_duration = 1000 * 1000 * 1000; // 1e9 nanoseconds = 1 second
   double epsilon = 0.01;
   double scaling_factor = 1.4;
 };
@@ -61,8 +65,12 @@ class RuntimeEstimationProgression {
 
 struct BenchmarkResult {
   uint64_t cycles = 0;
+  double standard_deviation = 0;
+  uint64_t min = UINT_MAX;
+  uint64_t max = 0;
   size_t samples = 0;
   size_t total_iterations = 0;
+  clock_t total_time = 0;
 };
 
 BenchmarkResult benchmark(const BenchmarkOptions &options,
@@ -107,7 +115,9 @@ class WrapperBenchmark : public Benchmark {
     constexpr auto RESET = "\033[0m";
     blog << GREEN << "[ RUN      ] " << RESET << name << '\n';
     blog << GREEN << "[       OK ] " << RESET << name << ": " << result.cycles
-         << " cycles, " << result.total_iterations << " iterations\n";
+         << " cycles, " << result.min << " min, " << result.max << " max, "
+         << result.total_iterations << " iterations, " << result.total_time
+         << " ns, " << (long)result.standard_deviation << " stddev\n";
   }
   const cpp::string_view get_name() const override { return name; }
 };
diff --git a/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp b/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp
index 8d9c958bb7ed4..4050bc0ec77b9 100644
--- a/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp
+++ b/libc/benchmarks/gpu/src/ctype/isalnum_benchmark.cpp
@@ -7,16 +7,3 @@ uint64_t BM_IsAlnum() {
   return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalnum, x);
 }
 BENCHMARK(LlvmLibcIsAlNumGpuBenchmark, IsAlnumWrapper, BM_IsAlnum);
-
-[[gnu::noinline]] static uint64_t single_input_function(int x) {
-  asm volatile("" ::"r"(x)); // prevent the compiler from optimizing out x
-  return x;
-}
-
-uint64_t BM_IsAlnumWithOverhead() {
-  char x = 'c';
-  return LIBC_NAMESPACE::latency(LIBC_NAMESPACE::isalnum, x) -
-         LIBC_NAMESPACE::latency(single_input_function, 0);
-}
-BENCHMARK(LlvmLibcIsAlNumGpuBenchmark, IsAlnumWithOverhead,
-          BM_IsAlnumWithOverhead);
diff --git a/libc/benchmarks/gpu/timing/nvptx/timing.h b/libc/benchmarks/gpu/timing/nvptx/timing.h
index 008432e6aa1d2..001bdd3686062 100644
--- a/libc/benchmarks/gpu/timing/nvptx/timing.h
+++ b/libc/benchmarks/gpu/timing/nvptx/timing.h
@@ -37,12 +37,7 @@ namespace LIBC_NAMESPACE {
 
 // Stimulate a simple function and obtain its latency in clock cycles on the
 // system. This function cannot be inlined or else it will disturb the very
-// deliccate balance of hard-coded dependencies.
-//
-// FIXME: This does not work in general on NVPTX because of further
-// optimizations ptxas performs. The only way to get consistent results is to
-// pass and extra "SHELL:-Xcuda-ptxas -O0" to CMake's compiler flag. This
-// negatively implacts performance but it is at least stable.
+// delicate balance of hard-coded dependencies.
 template <typename F, typename T>
 [[gnu::noinline]] static LIBC_INLINE uint64_t latency(F f, T t) {
   // We need to store the input somewhere to guarantee that the compiler will
@@ -53,7 +48,7 @@ template <typename F, typename T>
 
   // Get the current timestamp from the clock.
   gpu::sync_threads();
-  __nvvm_membar_sys();
+  gpu::memory_fence();
   uint64_t start = gpu::processor_clock();
 
   // This forces the compiler to load the input argument and run the clock cycle
@@ -70,7 +65,7 @@ template <typename F, typename T>
   // Obtain the current timestamp after running the calculation and force
   // ordering.
   uint64_t stop = gpu::processor_clock();
-  __nvvm_membar_sys();
+  gpu::memory_fence();
   gpu::sync_threads();
   asm volatile("" ::"r"(stop));
   volatile T output = result;
@@ -88,6 +83,7 @@ static LIBC_INLINE uint64_t latency(F f, T1 t1, T2 t2) {
   asm volatile("" ::"r"(arg), "r"(arg2));
 
   gpu::sync_threads();
+  gpu::memory_fence();
   uint64_t start = gpu::processor_clock();
 
   asm volatile("" ::"r"(arg), "r"(arg2), "llr"(start));
@@ -97,6 +93,7 @@ static LIBC_INLINE uint64_t latency(F f, T1 t1, T2 t2) {
   asm volatile("or.b32 %[v_reg], %[v_reg], 0;" ::[v_reg] "r"(result) :);
 
   uint64_t stop = gpu::processor_clock();
+  gpu::memory_fence();
   gpu::sync_threads();
   asm volatile("" ::"r"(stop));
   volatile auto output = result;

>From eff6fa935eb620977c01c3be30fd772e0166c926 Mon Sep 17 00:00:00 2001
From: jameshu15869 <jhudson15869 at gmail.com>
Date: Wed, 22 May 2024 16:08:39 -0400
Subject: [PATCH 5/6] fixed vector for benchmarks

---
 libc/benchmarks/CMakeLists.txt           | 114 ++++++++++++-----------
 libc/benchmarks/gpu/CMakeLists.txt       |   1 +
 libc/benchmarks/gpu/LibcGpuBenchmark.cpp |  16 +---
 libc/benchmarks/gpu/LibcGpuBenchmark.h   |   4 +-
 4 files changed, 65 insertions(+), 70 deletions(-)

diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt
index 8b51511e3b5cf..221d4e11d383d 100644
--- a/libc/benchmarks/CMakeLists.txt
+++ b/libc/benchmarks/CMakeLists.txt
@@ -1,14 +1,14 @@
 if(LIBC_TARGET_OS_IS_GPU)
-	add_subdirectory(gpu)
-	return()
+  add_subdirectory(gpu)
+  return()
 endif()
 
 find_package(Threads)
 
 set(LLVM_LINK_COMPONENTS
-	Support
-	TargetParser
-	)
+  Support
+  TargetParser
+)
 
 #==============================================================================
 # Add Unit Testing Support
@@ -16,35 +16,37 @@ set(LLVM_LINK_COMPONENTS
 
 function(add_libc_benchmark_unittest target_name)
 	if(NOT LLVM_INCLUDE_TESTS)
-	return()
+    return()
 	endif()
 
-	cmake_parse_arguments(
-	"LIBC_BENCHMARKS_UNITTEST"
-	"" # No optional arguments
-	"SUITE" # Single value arguments
-	"SRCS;DEPENDS" # Multi-value arguments
-	${ARGN}
+	cmake_parse_arguments(if(LIBC_TARGET_OS_IS_GPU)
+  add_subdirectory(gpu)
+  return()
+    "LIBC_BENCHMARKS_UNITTEST"
+    "" # No optional arguments
+    "SUITE" # Single value arguments
+    "SRCS;DEPENDS" # Multi-value arguments
+    ${ARGN}
 	)
 
-	add_executable(${target_name}
-	EXCLUDE_FROM_ALL
-	${LIBC_BENCHMARKS_UNITTEST_SRCS}
-	)
-	target_link_libraries(${target_name}
-	PRIVATE
-	llvm_gtest_main
-	llvm_gtest
-	${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
-	)
-	llvm_update_compile_flags(${target_name})
-
-	add_custom_command(
-	TARGET ${target_name}
-	POST_BUILD
-	COMMAND $<TARGET_FILE:${target_name}>
-	)
-	add_dependencies(libc-benchmark-util-tests ${target_name})
+  add_executable(${target_name}
+    EXCLUDE_FROM_ALL
+    ${LIBC_BENCHMARKS_UNITTEST_SRCS}
+  )
+  target_link_libraries(${target_name}
+    PRIVATE
+    llvm_gtest_main
+    llvm_gtest
+    ${LIBC_BENCHMARKS_UNITTEST_DEPENDS}
+  )
+  llvm_update_compile_flags(${target_name})
+
+  add_custom_command(
+    TARGET ${target_name}
+    POST_BUILD
+    COMMAND $<TARGET_FILE:${target_name}>
+  )
+  add_dependencies(libc-benchmark-util-tests ${target_name})
 endfunction()
 
 #==============================================================================
@@ -53,32 +55,32 @@ endfunction()
 
 include(ExternalProject)
 ExternalProject_Add(google-benchmark-libc
-	EXCLUDE_FROM_ALL ON
-	PREFIX google-benchmark-libc
-	SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
-	INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
-	CMAKE_CACHE_ARGS
-		-DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
-		-DBENCHMARK_ENABLE_LTO:BOOL=OFF
-		-DBENCHMARK_ENABLE_TESTING:BOOL=OFF
-		-DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
-		-DBENCHMARK_FORCE_WERROR:BOOL=OFF
-		-DBENCHMARK_USE_LIBCXX:BOOL=OFF
-		-DCMAKE_BUILD_TYPE:STRING=Release
-
-		-DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
-		-DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
-		-DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-		-DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-		-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
-		-DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
-
-		-DBUILD_SHARED_LIBS:BOOL=OFF
-		-DCMAKE_EXE_LINKER_FLAGS:STRING=-static
-
-		-DCMAKE_CXX_STANDARD:STRING=14
-		-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-	)
+  EXCLUDE_FROM_ALL ON
+  PREFIX google-benchmark-libc
+  SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
+  INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
+  CMAKE_CACHE_ARGS
+    -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
+    -DBENCHMARK_ENABLE_LTO:BOOL=OFF
+    -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
+    -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
+    -DBENCHMARK_FORCE_WERROR:BOOL=OFF
+    -DBENCHMARK_USE_LIBCXX:BOOL=OFF
+    -DCMAKE_BUILD_TYPE:STRING=Release
+
+    -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
+    -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
+    -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+    -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+    -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+    -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
+
+    -DBUILD_SHARED_LIBS:BOOL=OFF
+    -DCMAKE_EXE_LINKER_FLAGS:STRING=-static
+
+    -DCMAKE_CXX_STANDARD:STRING=14
+    -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+  )
 
 add_custom_target(libc-benchmark-util-tests)
 
diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt
index b9ca85393cc2e..51fc267df807d 100644
--- a/libc/benchmarks/gpu/CMakeLists.txt
+++ b/libc/benchmarks/gpu/CMakeLists.txt
@@ -48,6 +48,7 @@ add_unittest_framework_library(
     libc.src.__support.OSUtil.osutil
     libc.src.__support.uint128
     libc.src.___support.FPUtil.sqrt
+    libc.src.__support.fixedvector
     libc.src.time.clock
     libc.benchmarks.gpu.timing.timing
 )
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
index 3ecff18884b34..f8021c873242f 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.cpp
@@ -6,22 +6,16 @@
 namespace LIBC_NAMESPACE {
 namespace libc_gpu_benchmarks {
 
-Benchmark *Benchmark::start = nullptr;
-Benchmark *Benchmark::end = nullptr;
+FixedVector<Benchmark *, 64> benchmarks_to_run;
 
 void Benchmark::add_benchmark(Benchmark *benchmark) {
-  if (end == nullptr) {
-    start = benchmark;
-    end = benchmark;
-    return;
-  }
-  end->next = benchmark;
-  end = benchmark;
+  benchmarks_to_run.push_back(benchmark);
 }
 
 int Benchmark::run_benchmarks() {
-  for (Benchmark *b = start; b != nullptr; b = b->next)
-    b->run();
+  for (auto it = benchmarks_to_run.rbegin(), e = benchmarks_to_run.rend();
+       it != e; ++it)
+    (*it)->run();
   return 0;
 }
 
diff --git a/libc/benchmarks/gpu/LibcGpuBenchmark.h b/libc/benchmarks/gpu/LibcGpuBenchmark.h
index 798ae06086b1a..459e4d9b6ea98 100644
--- a/libc/benchmarks/gpu/LibcGpuBenchmark.h
+++ b/libc/benchmarks/gpu/LibcGpuBenchmark.h
@@ -6,6 +6,7 @@
 #include "src/__support/CPP/functional.h"
 #include "src/__support/CPP/limits.h"
 #include "src/__support/CPP/string_view.h"
+#include "src/__support/fixedvector.h"
 #include "src/time/clock.h"
 
 #include <stddef.h>
@@ -92,9 +93,6 @@ class Benchmark {
 private:
   virtual void run() = 0;
   virtual const cpp::string_view get_name() const = 0;
-
-  static Benchmark *start;
-  static Benchmark *end;
 };
 
 class WrapperBenchmark : public Benchmark {

>From 087290bc5d8c21f25368f09c095db4f87a683be3 Mon Sep 17 00:00:00 2001
From: jameshu15869 <jhudson15869 at gmail.com>
Date: Wed, 22 May 2024 16:27:44 -0400
Subject: [PATCH 6/6] refactor cmake files

---
 libc/benchmarks/CMakeLists.txt               | 188 +++++++++----------
 libc/benchmarks/gpu/CMakeLists.txt           |   3 +-
 libc/benchmarks/gpu/src/ctype/CMakeLists.txt |  28 +--
 libc/cmake/modules/LLVMLibCTestRules.cmake   |  27 +--
 4 files changed, 122 insertions(+), 124 deletions(-)

diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt
index 221d4e11d383d..0234ccb2a7a78 100644
--- a/libc/benchmarks/CMakeLists.txt
+++ b/libc/benchmarks/CMakeLists.txt
@@ -8,26 +8,24 @@ find_package(Threads)
 set(LLVM_LINK_COMPONENTS
   Support
   TargetParser
-)
+  )
 
 #==============================================================================
 # Add Unit Testing Support
 #==============================================================================
 
 function(add_libc_benchmark_unittest target_name)
-	if(NOT LLVM_INCLUDE_TESTS)
+  if(NOT LLVM_INCLUDE_TESTS)
     return()
-	endif()
+  endif()
 
-	cmake_parse_arguments(if(LIBC_TARGET_OS_IS_GPU)
-  add_subdirectory(gpu)
-  return()
+  cmake_parse_arguments(
     "LIBC_BENCHMARKS_UNITTEST"
     "" # No optional arguments
     "SUITE" # Single value arguments
     "SRCS;DEPENDS" # Multi-value arguments
     ${ARGN}
-	)
+  )
 
   add_executable(${target_name}
     EXCLUDE_FROM_ALL
@@ -55,99 +53,99 @@ endfunction()
 
 include(ExternalProject)
 ExternalProject_Add(google-benchmark-libc
-  EXCLUDE_FROM_ALL ON
-  PREFIX google-benchmark-libc
-  SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
-  INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
-  CMAKE_CACHE_ARGS
-    -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
-    -DBENCHMARK_ENABLE_LTO:BOOL=OFF
-    -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
-    -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
-    -DBENCHMARK_FORCE_WERROR:BOOL=OFF
-    -DBENCHMARK_USE_LIBCXX:BOOL=OFF
-    -DCMAKE_BUILD_TYPE:STRING=Release
-
-    -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
-    -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
-    -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-    -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-    -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
-    -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
-
-    -DBUILD_SHARED_LIBS:BOOL=OFF
-    -DCMAKE_EXE_LINKER_FLAGS:STRING=-static
-
-    -DCMAKE_CXX_STANDARD:STRING=14
-    -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-  )
+        EXCLUDE_FROM_ALL ON
+        PREFIX google-benchmark-libc
+        SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
+        INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
+        CMAKE_CACHE_ARGS
+          -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
+          -DBENCHMARK_ENABLE_LTO:BOOL=OFF
+          -DBENCHMARK_ENABLE_TESTING:BOOL=OFF
+          -DBENCHMARK_ENABLE_WERROR:BOOL=${LLVM_ENABLE_WERROR}
+          -DBENCHMARK_FORCE_WERROR:BOOL=OFF
+          -DBENCHMARK_USE_LIBCXX:BOOL=OFF
+          -DCMAKE_BUILD_TYPE:STRING=Release
+
+          -DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
+          -DCMAKE_SYSTEM_PROCESSOR:STRING=${CMAKE_SYSTEM_PROCESSOR}
+          -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
+          -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
+          -DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
+          -DCMAKE_FIND_ROOT_PATH:STRING=${CMAKE_FIND_ROOT_PATH}
+
+          -DBUILD_SHARED_LIBS:BOOL=OFF
+          -DCMAKE_EXE_LINKER_FLAGS:STRING=-static
+
+          -DCMAKE_CXX_STANDARD:STRING=14
+          -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
+        )
 
 add_custom_target(libc-benchmark-util-tests)
 
 # libc-benchmark
 add_library(libc-benchmark
-	STATIC
-	EXCLUDE_FROM_ALL
-	LibcBenchmark.cpp
-	LibcBenchmark.h
+    STATIC
+    EXCLUDE_FROM_ALL
+    LibcBenchmark.cpp
+    LibcBenchmark.h
 )
 
 target_include_directories(libc-benchmark
-	PUBLIC ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}
+    PUBLIC ${LLVM_INCLUDE_DIR} ${LLVM_MAIN_INCLUDE_DIR}
 )
 target_link_libraries(libc-benchmark
-	PUBLIC
-	benchmark::benchmark
-		LLVMSupport
-	LLVMTargetParser
-	Threads::Threads
+    PUBLIC
+    benchmark::benchmark
+    LLVMSupport
+    LLVMTargetParser
+    Threads::Threads
 )
 add_dependencies(libc-benchmark google-benchmark-libc)
 llvm_update_compile_flags(libc-benchmark)
 
 add_libc_benchmark_unittest(libc-benchmark-test
-	SRCS LibcBenchmarkTest.cpp
-	DEPENDS libc-benchmark
+    SRCS LibcBenchmarkTest.cpp
+    DEPENDS libc-benchmark
 )
 
 # libc-memory-benchmark
 add_library(libc-memory-benchmark
-	STATIC
-	EXCLUDE_FROM_ALL
-	LibcMemoryBenchmark.cpp
-	LibcMemoryBenchmark.h
-	LibcFunctionPrototypes.h
-	MemorySizeDistributions.cpp
-	MemorySizeDistributions.h
+    STATIC
+    EXCLUDE_FROM_ALL
+    LibcMemoryBenchmark.cpp
+    LibcMemoryBenchmark.h
+    LibcFunctionPrototypes.h
+    MemorySizeDistributions.cpp
+    MemorySizeDistributions.h
 )
 target_include_directories(libc-memory-benchmark
-	PUBLIC
-	${CMAKE_CURRENT_SOURCE_DIR}
+    PUBLIC
+    ${CMAKE_CURRENT_SOURCE_DIR}
 )
 target_link_libraries(libc-memory-benchmark
-	PUBLIC
-	libc-benchmark
+    PUBLIC
+    libc-benchmark
 )
 llvm_update_compile_flags(libc-memory-benchmark)
 
 add_libc_benchmark_unittest(libc-memory-benchmark-test
-	SRCS LibcMemoryBenchmarkTest.cpp
-	DEPENDS libc-memory-benchmark
+    SRCS LibcMemoryBenchmarkTest.cpp
+    DEPENDS libc-memory-benchmark
 )
 
 # json
 add_library(json
-	STATIC
-	EXCLUDE_FROM_ALL
-	JSON.cpp
-	JSON.h
+    STATIC
+    EXCLUDE_FROM_ALL
+    JSON.cpp
+    JSON.h
 )
 target_link_libraries(json PUBLIC libc-memory-benchmark)
 llvm_update_compile_flags(json)
 
 add_libc_benchmark_unittest(json-test
-	SRCS JSONTest.cpp
-	DEPENDS json
+    SRCS JSONTest.cpp
+    DEPENDS json
 )
 
 #==============================================================================
@@ -156,25 +154,25 @@ add_libc_benchmark_unittest(json-test
 
 # Benchmark all implementations that can run on the target CPU.
 function(add_libc_multi_impl_benchmark name)
-	get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
-	foreach(fq_config_name IN LISTS fq_implementations)
-	get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)
-	cpu_supports(can_run "${required_cpu_features}")
-	if(can_run)
-	set(benchmark_name ${fq_config_name}_benchmark)
-	add_executable(${benchmark_name}
-		EXCLUDE_FROM_ALL
-		LibcMemoryBenchmarkMain.cpp
-	)
-	get_target_property(entrypoint_object_file ${fq_config_name} "OBJECT_FILE_RAW")
-	target_link_libraries(${benchmark_name} PUBLIC json ${entrypoint_object_file})
-	string(TOUPPER ${name} name_upper)
-	target_compile_definitions(${benchmark_name} PRIVATE "-DLIBC_BENCHMARK_FUNCTION_${name_upper}=LIBC_NAMESPACE::${name}" "-DLIBC_BENCHMARK_FUNCTION_NAME=\"${fq_config_name}\"")
-	llvm_update_compile_flags(${benchmark_name})
-	else()
-		message(STATUS "Skipping benchmark for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")
-	endif()
-	endforeach()
+  get_property(fq_implementations GLOBAL PROPERTY ${name}_implementations)
+  foreach(fq_config_name IN LISTS fq_implementations)
+    get_target_property(required_cpu_features ${fq_config_name} REQUIRE_CPU_FEATURES)
+    cpu_supports(can_run "${required_cpu_features}")
+    if(can_run)
+        set(benchmark_name ${fq_config_name}_benchmark)
+        add_executable(${benchmark_name}
+            EXCLUDE_FROM_ALL
+            LibcMemoryBenchmarkMain.cpp
+        )
+        get_target_property(entrypoint_object_file ${fq_config_name} "OBJECT_FILE_RAW")
+        target_link_libraries(${benchmark_name} PUBLIC json ${entrypoint_object_file})
+        string(TOUPPER ${name} name_upper)
+        target_compile_definitions(${benchmark_name} PRIVATE "-DLIBC_BENCHMARK_FUNCTION_${name_upper}=LIBC_NAMESPACE::${name}" "-DLIBC_BENCHMARK_FUNCTION_NAME=\"${fq_config_name}\"")
+        llvm_update_compile_flags(${benchmark_name})
+    else()
+      message(STATUS "Skipping benchmark for '${fq_config_name}' insufficient host cpu features '${required_cpu_features}'")
+    endif()
+  endforeach()
 endfunction()
 
 add_libc_multi_impl_benchmark(bcmp)
@@ -192,20 +190,20 @@ add_libc_multi_impl_benchmark(memset)
 # libc memory functions compiled for the host machine. This is useful to
 # continuously monitor the performance of the memory functions.
 add_executable(libc.benchmarks.memory_functions.opt_host
-	EXCLUDE_FROM_ALL
-	LibcMemoryGoogleBenchmarkMain.cpp
-	LibcDefaultImplementations.cpp
+  EXCLUDE_FROM_ALL
+  LibcMemoryGoogleBenchmarkMain.cpp
+  LibcDefaultImplementations.cpp
 )
 target_link_libraries(libc.benchmarks.memory_functions.opt_host
-	PRIVATE
-	libc-memory-benchmark
-	libc.src.string.memcmp_opt_host.__internal__
-	libc.src.string.bcmp_opt_host.__internal__
-	libc.src.string.memcpy_opt_host.__internal__
-	libc.src.string.memset_opt_host.__internal__
-	libc.src.string.bzero_opt_host.__internal__
-	libc.src.string.memmove_opt_host.__internal__
-	benchmark_main
+  PRIVATE
+  libc-memory-benchmark
+  libc.src.string.memcmp_opt_host.__internal__
+  libc.src.string.bcmp_opt_host.__internal__
+  libc.src.string.memcpy_opt_host.__internal__
+  libc.src.string.memset_opt_host.__internal__
+  libc.src.string.bzero_opt_host.__internal__
+  libc.src.string.memmove_opt_host.__internal__
+  benchmark_main
 )
 llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host)
 
diff --git a/libc/benchmarks/gpu/CMakeLists.txt b/libc/benchmarks/gpu/CMakeLists.txt
index 51fc267df807d..9ed45eedc402e 100644
--- a/libc/benchmarks/gpu/CMakeLists.txt
+++ b/libc/benchmarks/gpu/CMakeLists.txt
@@ -13,9 +13,8 @@ function(add_benchmark benchmark_name)
   if(NOT libc.src.time.clock IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS)
     message(FATAL_ERROR "target does not support clock")
   endif()
-  add_libc_hermetic_test(
+  add_libc_hermetic(
     ${benchmark_name}
-    IS_BENCHMARK
     LINK_LIBRARIES
       LibcGpuBenchmark.hermetic
       ${BENCHMARK_LINK_LIBRARIES}
diff --git a/libc/benchmarks/gpu/src/ctype/CMakeLists.txt b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
index 8d448b8ced955..79f01425770da 100644
--- a/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
+++ b/libc/benchmarks/gpu/src/ctype/CMakeLists.txt
@@ -1,21 +1,21 @@
 add_custom_target(libc-gpu-ctype-benchmarks)
 
 add_benchmark(
-	isalnum_benchmark
-	SUITE
-		libc-gpu-ctype-benchmarks
-	SRCS
-		isalnum_benchmark.cpp
-	DEPENDS
-		libc.src.ctype.isalnum
+  isalnum_benchmark
+  SUITE
+    libc-gpu-ctype-benchmarks
+  SRCS
+    isalnum_benchmark.cpp
+  DEPENDS
+    libc.src.ctype.isalnum
 )
 
 add_benchmark(
-	isalpha_benchmark
-	SUITE
-		libc-gpu-ctype-benchmarks
-	SRCS
-		isalpha_benchmark.cpp
-	DEPENDS
-		libc.src.ctype.isalpha
+  isalpha_benchmark
+  SUITE
+    libc-gpu-ctype-benchmarks
+  SRCS
+    isalpha_benchmark.cpp
+  DEPENDS
+    libc.src.ctype.isalpha
 )
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index 3d4f18a1291a5..4db11fe835569 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -526,12 +526,15 @@ function(add_integration_test test_name)
   add_dependencies(${INTEGRATION_TEST_SUITE} ${fq_target_name})
 endfunction(add_integration_test)
 
-# Rule to add a hermetic test. A hermetic test is one whose executable is fully
+# Rule to add a hermetic program. A hermetic program is one whose executable is fully
 # statically linked and consists of pieces drawn only from LLVM's libc. Nothing,
 # including the startup objects, come from the system libc.
 #
+# For the GPU, these can be either tests or benchmarks, depending on the value
+# of the LINK_LIBRARIES arg.
+#
 # Usage:
-#   add_libc_hermetic_test(
+#   add_libc_hermetic(
 #     <target name>
 #     SUITE <the suite to which the test should belong>
 #     SRCS <src1.cpp> [src2.cpp ...]
@@ -543,14 +546,14 @@ endfunction(add_integration_test)
 #     LINK_LIBRARIES <list of linking libraries for this target>
 #     LOADER_ARGS <list of special args to loaders (like the GPU loader)>
 #   )
-function(add_libc_hermetic_test test_name)
+function(add_libc_hermetic test_name)
   if(NOT TARGET libc.startup.${LIBC_TARGET_OS}.crt1)
     message(VERBOSE "Skipping ${fq_target_name} as it is not available on ${LIBC_TARGET_OS}.")
     return()
   endif()
   cmake_parse_arguments(
     "HERMETIC_TEST"
-    "IS_BENCHMARK" # Optional arguments
+    "" # No optional arguments
     "SUITE" # Single value arguments
     "SRCS;HDRS;DEPENDS;ARGS;ENV;COMPILE_OPTIONS;LINK_LIBRARIES;LOADER_ARGS" # Multi-value arguments
     ${ARGN}
@@ -651,13 +654,6 @@ function(add_libc_hermetic_test test_name)
     endif()
   endforeach()
 
-  # Benchmarks requires a separate library with a different `main` function
-  if(HERMETIC_TEST_IS_BENCHMARK)
-    list(APPEND link_libraries LibcGpuBenchmark.hermetic)
-  else()
-    list(APPEND link_libraries LibcTest.hermetic)
-  endif()
-
   if(LIBC_TARGET_ARCHITECTURE_IS_AMDGPU)
     target_link_options(${fq_build_target_name} PRIVATE
       ${LIBC_COMPILE_OPTIONS_DEFAULT}
@@ -712,7 +708,7 @@ function(add_libc_hermetic_test test_name)
 
   add_dependencies(${HERMETIC_TEST_SUITE} ${fq_target_name})
   add_dependencies(libc-hermetic-tests ${fq_target_name})
-endfunction(add_libc_hermetic_test)
+endfunction(add_libc_hermetic)
 
 # A convenience function to add both a unit test as well as a hermetic test.
 function(add_libc_test test_name)
@@ -727,7 +723,12 @@ function(add_libc_test test_name)
     add_libc_unittest(${test_name}.__unit__ ${LIBC_TEST_UNPARSED_ARGUMENTS})
   endif()
   if(LIBC_ENABLE_HERMETIC_TESTS AND NOT LIBC_TEST_UNIT_TEST_ONLY)
-    add_libc_hermetic_test(${test_name}.__hermetic__ ${LIBC_TEST_UNPARSED_ARGUMENTS})
+    add_libc_hermetic(
+      ${test_name}.__hermetic__
+      LINK_LIBRARIES
+        LibcTest.hermetic
+      ${LIBC_TEST_UNPARSED_ARGUMENTS}
+    )
     get_fq_target_name(${test_name} fq_test_name)
     if(TARGET ${fq_test_name}.__hermetic__ AND TARGET ${fq_test_name}.__unit__)
       # Tests like the file tests perform file operations on disk file. If we



More information about the libc-commits mailing list