[libc-commits] [libc] [libc][benchmark] allow benchmark to be built without llvm support (PR #200951)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Mon Jun 1 14:46:31 PDT 2026


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/200951

>From 4758f8b095a88ba6dd469f5deb52d13f8a8e3839 Mon Sep 17 00:00:00 2001
From: Yifan Zhu <yfzhu at google.com>
Date: Mon, 1 Jun 2026 14:42:33 -0700
Subject: [PATCH] [libc][benchmark] allow benchmark to be built without llvm
 support

---
 libc/benchmarks/CMakeLists.txt                | 148 ++++++++++++------
 libc/benchmarks/LibcBenchmark.cpp             |  27 ++++
 libc/benchmarks/LibcBenchmark.h               |  11 +-
 libc/benchmarks/LibcMemoryBenchmark.cpp       |  27 +++-
 libc/benchmarks/LibcMemoryBenchmark.h         |  17 +-
 .../LibcMemoryGoogleBenchmarkMain.cpp         |   8 +
 libc/benchmarks/MemorySizeDistributions.cpp   |  14 ++
 7 files changed, 192 insertions(+), 60 deletions(-)

diff --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt
index 65c7cd76fad29..ebb270c7c2dc8 100644
--- a/libc/benchmarks/CMakeLists.txt
+++ b/libc/benchmarks/CMakeLists.txt
@@ -10,16 +10,28 @@ endif()
 
 find_package(Threads)
 
-set(LLVM_LINK_COMPONENTS
-  Support
-  TargetParser
-  )
+option(LIBC_BENCHMARKS_HAS_LLVM_SUPPORT "Avoid LLVM Support dependency and reporting CPU details" ON)
+
+if(NOT TARGET LLVMSupport OR NOT TARGET LLVMTargetParser)
+  set(LIBC_BENCHMARKS_HAS_LLVM_SUPPORT OFF CACHE BOOL "Avoid LLVM Support dependency and reporting CPU details" FORCE)
+endif()
+
+if(LIBC_BENCHMARKS_HAS_LLVM_SUPPORT)
+  set(LLVM_LINK_COMPONENTS
+    Support
+    TargetParser
+    )
+endif()
 
 #==============================================================================
 # Add Unit Testing Support
 #==============================================================================
 
-make_gtest_target()
+if(COMMAND build_gtest)
+  build_gtest()
+elseif(COMMAND make_gtest_target)
+  make_gtest_target()
+endif()
 
 function(add_libc_benchmark_unittest target_name)
   if(NOT LLVM_INCLUDE_TESTS)
@@ -64,6 +76,9 @@ ExternalProject_Add(google-benchmark-libc
         PREFIX google-benchmark-libc
         SOURCE_DIR ${LLVM_THIRD_PARTY_DIR}/benchmark
         INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc
+        BUILD_BYPRODUCTS
+          ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/lib/libbenchmark.a
+          ${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/lib/libbenchmark_main.a
         CMAKE_CACHE_ARGS
           -DBENCHMARK_ENABLE_EXCEPTIONS:BOOL=OFF
           -DBENCHMARK_ENABLE_LTO:BOOL=OFF
@@ -87,6 +102,26 @@ ExternalProject_Add(google-benchmark-libc
           -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
         )
 
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/include")
+
+if(NOT TARGET benchmark::benchmark)
+  add_library(benchmark::benchmark STATIC IMPORTED)
+  set_target_properties(benchmark::benchmark PROPERTIES
+    IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/lib/libbenchmark.a"
+    INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/include"
+  )
+  add_dependencies(benchmark::benchmark google-benchmark-libc)
+endif()
+
+if(NOT TARGET benchmark_main)
+  add_library(benchmark_main STATIC IMPORTED)
+  set_target_properties(benchmark_main PROPERTIES
+    IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/lib/libbenchmark_main.a"
+    INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/google-benchmark-libc/include"
+  )
+  add_dependencies(benchmark_main google-benchmark-libc)
+endif()
+
 add_custom_target(libc-benchmark-util-tests)
 
 # libc-benchmark
@@ -103,10 +138,18 @@ target_include_directories(libc-benchmark
 target_link_libraries(libc-benchmark
     PUBLIC
     benchmark::benchmark
-    LLVMSupport
-    LLVMTargetParser
     Threads::Threads
 )
+if(LIBC_BENCHMARKS_HAS_LLVM_SUPPORT)
+  target_link_libraries(libc-benchmark
+      PUBLIC
+      LLVMSupport
+      LLVMTargetParser
+  )
+  target_compile_definitions(libc-benchmark PUBLIC "LIBC_BENCHMARKS_HAS_LLVM_SUPPORT")
+else()
+  target_compile_definitions(libc-benchmark PUBLIC "LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING=1")
+endif()
 add_dependencies(libc-benchmark google-benchmark-libc)
 llvm_update_compile_flags(libc-benchmark)
 
@@ -141,54 +184,56 @@ add_libc_benchmark_unittest(libc-memory-benchmark-test
     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)
+if(LIBC_BENCHMARKS_HAS_LLVM_SUPPORT)
+  # 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
-)
+  add_libc_benchmark_unittest(json-test
+      SRCS JSONTest.cpp
+      DEPENDS json
+  )
 
-#==============================================================================
-# Benchmarking tool
-#==============================================================================
+  #==============================================================================
+  # 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()
+  # 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)
+  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)
+endif()
 
 #==============================================================================
 # Google Benchmarking tool
@@ -214,3 +259,4 @@ target_link_libraries(libc.benchmarks.memory_functions.opt_host
   benchmark_main
 )
 llvm_update_compile_flags(libc.benchmarks.memory_functions.opt_host)
+add_dependencies(libc.benchmarks.memory_functions.opt_host google-benchmark-libc)
diff --git a/libc/benchmarks/LibcBenchmark.cpp b/libc/benchmarks/LibcBenchmark.cpp
index 014b855fe987f..a5bca1f71ebea 100644
--- a/libc/benchmarks/LibcBenchmark.cpp
+++ b/libc/benchmarks/LibcBenchmark.cpp
@@ -8,7 +8,9 @@
 
 #include "LibcBenchmark.h"
 #include "llvm/ADT/StringRef.h"
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
 #include "llvm/TargetParser/Host.h"
+#endif
 
 namespace llvm {
 namespace libc_benchmarks {
@@ -25,7 +27,11 @@ HostState HostState::get() {
   const auto &CpuInfo = benchmark::CPUInfo::Get();
   HostState H;
   H.CpuFrequency = CpuInfo.cycles_per_second;
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
   H.CpuName = llvm::sys::getHostCPUName().str();
+#else
+  H.CpuName = "";
+#endif
   for (const auto &BenchmarkCacheInfo : CpuInfo.caches) {
     CacheInfo CI;
     CI.Type = BenchmarkCacheInfo.type;
@@ -39,3 +45,24 @@ HostState HostState::get() {
 
 } // namespace libc_benchmarks
 } // namespace llvm
+
+#ifndef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
+#include "llvm/ADT/Twine.h"
+#include <cstdlib>
+#include <iostream>
+
+namespace llvm {
+void report_fatal_error(const char *reason, bool gen_crash_diag) {
+  std::cerr << "Fatal error: " << reason << std::endl;
+  std::abort();
+}
+void report_fatal_error(StringRef reason, bool gen_crash_diag) {
+  std::cerr << "Fatal error: " << reason.str() << std::endl;
+  std::abort();
+}
+void report_fatal_error(const Twine &reason, bool gen_crash_diag) {
+  std::cerr << "Fatal error: (twine reason)" << std::endl;
+  std::abort();
+}
+} // namespace llvm
+#endif
diff --git a/libc/benchmarks/LibcBenchmark.h b/libc/benchmarks/LibcBenchmark.h
index 6b1556721e416..a790c3ad43d6d 100644
--- a/libc/benchmarks/LibcBenchmark.h
+++ b/libc/benchmarks/LibcBenchmark.h
@@ -39,6 +39,8 @@
 #include <cstdint>
 #include <optional>
 
+#include "llvm/Support/ErrorHandling.h"
+
 namespace llvm {
 namespace libc_benchmarks {
 
@@ -95,11 +97,18 @@ struct BenchmarkState {
                       // current samples.
 };
 
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
+using BenchmarkLogType = llvm::SmallVector<BenchmarkState, 16>;
+#else
+#include <vector>
+using BenchmarkLogType = std::vector<BenchmarkState>;
+#endif
+
 // A lightweight result for a benchmark.
 struct BenchmarkResult {
   BenchmarkStatus TerminationStatus = BenchmarkStatus::Running;
   Duration BestGuess = {};
-  std::optional<llvm::SmallVector<BenchmarkState, 16>> MaybeBenchmarkLog;
+  std::optional<BenchmarkLogType> MaybeBenchmarkLog;
 };
 
 // Stores information about a cache in the host memory system.
diff --git a/libc/benchmarks/LibcMemoryBenchmark.cpp b/libc/benchmarks/LibcMemoryBenchmark.cpp
index 9307ee45b2853..a0500ff0201df 100644
--- a/libc/benchmarks/LibcMemoryBenchmark.cpp
+++ b/libc/benchmarks/LibcMemoryBenchmark.cpp
@@ -8,10 +8,13 @@
 
 #include "LibcMemoryBenchmark.h"
 #include "llvm/ADT/SmallVector.h"
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/ErrorHandling.h"
+#endif
 #include "llvm/Support/MathExtras.h"
 #include <algorithm>
+#include <optional>
 
 namespace llvm {
 namespace libc_benchmarks {
@@ -61,7 +64,8 @@ MismatchOffsetDistribution::MismatchOffsetDistribution(size_t BufferSize,
       std::uniform_int_distribution<size_t>(0, MismatchIndices.size() - 1);
 }
 
-static size_t getL1DataCacheSize() {
+static std::optional<size_t> getL1DataCacheSize() {
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
   const std::vector<CacheInfo> &CacheInfos = HostState::get().Caches;
   const auto IsL1DataCache = [](const CacheInfo &CI) {
     return CI.Type == "Data" && CI.Level == 1;
@@ -70,6 +74,9 @@ static size_t getL1DataCacheSize() {
   if (CacheIt != CacheInfos.end())
     return CacheIt->Size;
   report_fatal_error("Unable to read L1 Cache Data Size");
+#else
+  return std::nullopt;
+#endif
 }
 
 static constexpr int64_t KiB = 1024;
@@ -77,7 +84,9 @@ static constexpr int64_t ParameterStorageBytes = 4 * KiB;
 static constexpr int64_t L1LeftAsideBytes = 1 * KiB;
 
 static size_t getAvailableBufferSize() {
-  return getL1DataCacheSize() - L1LeftAsideBytes - ParameterStorageBytes;
+  auto L1Size = getL1DataCacheSize();
+  return (L1Size ? *L1Size : 32 * 1024) - L1LeftAsideBytes -
+         ParameterStorageBytes;
 }
 
 ParameterBatch::ParameterBatch(size_t BufferCount)
@@ -88,7 +97,8 @@ ParameterBatch::ParameterBatch(size_t BufferCount)
     report_fatal_error("Not enough L1 cache");
   const size_t ParameterBytes = Parameters.size() * sizeof(ParameterType);
   const size_t BufferBytes = BufferSize * BufferCount;
-  if (ParameterBytes + BufferBytes + L1LeftAsideBytes > getL1DataCacheSize())
+  auto L1Size = getL1DataCacheSize();
+  if (L1Size && ParameterBytes + BufferBytes + L1LeftAsideBytes > *L1Size)
     report_fatal_error(
         "We're splitting a buffer of the size of the L1 cache between a data "
         "buffer and a benchmark parameters buffer, so by construction the "
@@ -103,7 +113,8 @@ size_t ParameterBatch::getBatchBytes() const {
 }
 
 void ParameterBatch::checkValid(const ParameterType &P) const {
-  if (P.OffsetBytes + P.SizeBytes >= BufferSize)
+  if (P.OffsetBytes + P.SizeBytes >= BufferSize) {
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
     report_fatal_error(
         llvm::Twine("Call would result in buffer overflow: Offset=")
             .concat(llvm::Twine(P.OffsetBytes))
@@ -111,6 +122,14 @@ void ParameterBatch::checkValid(const ParameterType &P) const {
             .concat(llvm::Twine(P.SizeBytes))
             .concat(", BufferSize=")
             .concat(llvm::Twine(BufferSize)));
+#else
+    std::string Message = "Call would result in buffer overflow: Offset=" +
+                          std::to_string(P.OffsetBytes) +
+                          ", Size=" + std::to_string(P.SizeBytes) +
+                          ", BufferSize=" + std::to_string(BufferSize);
+    report_fatal_error(Message.c_str());
+#endif
+  }
 }
 
 CopySetup::CopySetup()
diff --git a/libc/benchmarks/LibcMemoryBenchmark.h b/libc/benchmarks/LibcMemoryBenchmark.h
index 5ba8b936a0caf..eca50d618ad64 100644
--- a/libc/benchmarks/LibcMemoryBenchmark.h
+++ b/libc/benchmarks/LibcMemoryBenchmark.h
@@ -21,6 +21,7 @@
 #include <cstdint>
 #include <optional>
 #include <random>
+#include <vector>
 
 namespace llvm {
 namespace libc_benchmarks {
@@ -83,7 +84,7 @@ struct Runtime {
 
   // The benchmark options that were used to perform the measurement.
   // This is decided by the framework.
-  BenchmarkOptions BenchmarkOptions;
+  struct BenchmarkOptions BenchmarkOptions;
 };
 
 //--------
@@ -93,7 +94,7 @@ struct Runtime {
 // The root object containing all the data (configuration and measurements).
 struct Study {
   std::string StudyName;
-  Runtime Runtime;
+  struct Runtime Runtime;
   StudyConfiguration Configuration;
   std::vector<Duration> Measurements;
 };
@@ -139,12 +140,20 @@ class OffsetDistribution {
   }
 };
 
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
+using MismatchIndicesType = llvm::SmallVector<uint32_t, 16>;
+using MismatchIndicesImplType = llvm::SmallVectorImpl<uint32_t>;
+#else
+using MismatchIndicesType = std::vector<uint32_t>;
+using MismatchIndicesImplType = std::vector<uint32_t>;
+#endif
+
 // Helper to generate random buffer offsets that satisfy the configuration
 // constraints. It is specifically designed to benchmark `memcmp` functions
 // where we may want the Nth byte to differ.
 class MismatchOffsetDistribution {
   std::uniform_int_distribution<size_t> MismatchIndexSelector;
-  llvm::SmallVector<uint32_t, 16> MismatchIndices;
+  MismatchIndicesType MismatchIndices;
   const uint32_t MismatchAt;
 
 public:
@@ -153,7 +162,7 @@ class MismatchOffsetDistribution {
 
   explicit operator bool() const { return !MismatchIndices.empty(); }
 
-  const llvm::SmallVectorImpl<uint32_t> &getMismatchIndices() const {
+  const MismatchIndicesImplType &getMismatchIndices() const {
     return MismatchIndices;
   }
 
diff --git a/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp b/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp
index 164708ad1a05a..db75a6e7453bc 100644
--- a/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp
+++ b/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp
@@ -3,7 +3,9 @@
 #include "MemorySizeDistributions.h"
 #include "benchmark/benchmark.h"
 #include "llvm/ADT/ArrayRef.h"
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
 #include "llvm/ADT/Twine.h"
+#endif
 #include <chrono>
 #include <cstdint>
 #include <random>
@@ -11,7 +13,9 @@
 
 using llvm::Align;
 using llvm::ArrayRef;
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
 using llvm::Twine;
+#endif
 using llvm::libc_benchmarks::BzeroConfiguration;
 using llvm::libc_benchmarks::ComparisonSetup;
 using llvm::libc_benchmarks::CopySetup;
@@ -53,7 +57,11 @@ template <typename SetupType, typename ConfigurationType> struct Runner {
         (State.iterations() * Setup.getBatchBytes()) / Setup.BatchSize;
     State.SetBytesProcessed(TotalBytes);
     State.SetItemsProcessed(State.iterations());
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
     State.SetLabel((Twine(Configuration.Name) + "," + Distribution.Name).str());
+#else
+    State.SetLabel(Configuration.Name.str() + "," + Distribution.Name.str());
+#endif
     State.counters["bytes_per_cycle"] = benchmark::Counter(
         TotalBytes / benchmark::CPUInfo::Get().cycles_per_second,
         benchmark::Counter::kIsRate);
diff --git a/libc/benchmarks/MemorySizeDistributions.cpp b/libc/benchmarks/MemorySizeDistributions.cpp
index e29b3710f7367..9e7469cc81a50 100644
--- a/libc/benchmarks/MemorySizeDistributions.cpp
+++ b/libc/benchmarks/MemorySizeDistributions.cpp
@@ -1,7 +1,12 @@
 #include "MemorySizeDistributions.h"
 
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
+#else
+#include <iostream>
+#include <sstream>
+#endif
 
 namespace llvm {
 namespace libc_benchmarks {
@@ -189,6 +194,7 @@ getDistributionOrDie(ArrayRef<MemorySizeDistribution> Distributions,
     if (MSD.Name == Name)
       return MSD;
 
+#ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT
   std::string Message;
   raw_string_ostream Stream(Message);
   Stream << "Unknown MemorySizeDistribution '" << Name
@@ -196,6 +202,14 @@ getDistributionOrDie(ArrayRef<MemorySizeDistribution> Distributions,
   for (const auto &MSD : Distributions)
     Stream << "'" << MSD.Name << "'\n";
   report_fatal_error(Message);
+#else
+  std::stringstream Stream;
+  Stream << "Unknown MemorySizeDistribution '" << std::string(Name)
+         << "', available distributions:\n";
+  for (const auto &MSD : Distributions)
+    Stream << "'" << MSD.Name.str() << "'\n";
+  report_fatal_error(Stream.str());
+#endif
 }
 
 } // namespace libc_benchmarks



More information about the libc-commits mailing list