From 0633394dddf37ac2e90737380afe42444fefb94a Mon Sep 17 00:00:00 2001 From: Joana Cruz Date: Wed, 11 Dec 2024 09:48:46 +0000 Subject: [PATCH] Add libm benchmarks Extended current benchmark tool with support to benchmark of libm functions. Libm benchmark is enabled in all functions listed in benchlibm.cpp. It interfaces with the rest of the existing tool through benchmark_callers_libm.hpp (defines macros which simplify how the list of functions to benchmark looks like as it groups functions by precision/accuracy/variant). The tool is integrated with SLEEF via CMake, meaning it can be built automatically when SLEEF is built. To enable that, pass CMake argument -DSLEEF_BUILD_BENCH=ON and -DSLEEF_BUILD_BENCH_REF=ON. Note this option is only enabled on Linux OS. --- CMakeLists.txt | 10 +++ docs/4-tools/README.md | 11 ++- src/libm-benchmarks/CMakeLists.txt | 24 ++++--- src/libm-benchmarks/README.md | 9 +++ src/libm-benchmarks/benchlibm.cpp | 69 +++++++++++++++++++ .../benchmark_callers_libm.hpp | 46 +++++++++++++ src/libm-benchmarks/benchmark_templates.hpp | 16 +++++ src/libm-benchmarks/gen_input.hpp | 1 + src/libm-benchmarks/type_defs.hpp | 6 +- 9 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 src/libm-benchmarks/benchlibm.cpp create mode 100644 src/libm-benchmarks/benchmark_callers_libm.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f9912bc4..10c321fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ option(SLEEF_BUILD_GNUABI_LIBS "libsleefgnuabi will be built." ON) option(SLEEF_BUILD_SCALAR_LIB "libsleefscalar will be built." OFF) option(SLEEF_BUILD_TESTS "Tests will be built." ON) option(SLEEF_BUILD_BENCH "Bench will be built." OFF) +option(SLEEF_BUILD_BENCH_REF "Benchmark script for reference (e.g. system libm) will be built." OFF) option(SLEEF_BUILD_INLINE_HEADERS "Build header for inlining whole SLEEF functions" OFF) option(SLEEF_TEST_ALL_IUT "Perform tests on implementations with all vector extensions" OFF) @@ -42,6 +43,15 @@ if (SLEEF_BUILD_BENCH) set(SLEEF_ENABLE_CXX ON) endif () +if (SLEEF_BUILD_BENCH_REF) + if (NOT SLEEF_BUILD_BENCH) + message(FATAL_ERROR "SLEEF_BUILD_BENCH must be on when SLEEF_BUILD_BENCH_REF is enabled.") + endif () + if(NOT CMAKE_SYSTEM_NAME MATCHES Linux) + message(FATAL_ERROR "Libm benchmarking not supported in this OS.") + endif() +endif () + if (DEFINED SLEEF_BUILD_SHARED_LIBS) set(BUILD_SHARED_LIBS ${SLEEF_BUILD_SHARED_LIBS}) endif () diff --git a/docs/4-tools/README.md b/docs/4-tools/README.md index 517ea0b4..c83764dc 100644 --- a/docs/4-tools/README.md +++ b/docs/4-tools/README.md @@ -153,4 +153,13 @@ executables may be built (according to feature detection): These will benchmark 256bit and 512bit vector implementations for vector functions respectively. Note these executables can also be used to benchmark scalar -functions. \ No newline at end of file +functions. + +

Benchmarking libm

+This tool can also benchmark libm functions listed in +`benchlibm.cpp`. +To enable this, pass on extra build option `-DSLEEF_BUILD_BENCH_REF=ON` +(on top of `-DSLEEF_BUILD_BENCH` from before). +This will produce a new script `./build/bin/benchlibm128`. +You can interact with this in a similar fashion as described for +`./build/bin/benchsleef128`. \ No newline at end of file diff --git a/src/libm-benchmarks/CMakeLists.txt b/src/libm-benchmarks/CMakeLists.txt index 81b59b9b..379e5414 100644 --- a/src/libm-benchmarks/CMakeLists.txt +++ b/src/libm-benchmarks/CMakeLists.txt @@ -25,27 +25,35 @@ link_directories(${sleef_BINARY_DIR}/lib) # libsleef set(EXTRA_CFLAGS -Wall -O2 -Wno-attributes) -set(BENCH_SRC_FILE "benchsleef.cpp" "benchmark_callers.hpp" "benchmark_templates.hpp" "gen_input.hpp" "type_defs.hpp") +set(BENCH_HPP_SRC_FILES "benchmark_callers.hpp" "benchmark_templates.hpp" "gen_input.hpp" "type_defs.hpp") set(BENCH_PROPERTIES C_STANDARD 99 CXX_STANDARD 17) -set(BENCH_LIBS benchmark sleef Threads::Threads) # Link Google Benchmark and sleef to the project +set(GOOGLE_BENCH_LIBS benchmark Threads::Threads) # Link Google Benchmark to the project # Add source to this project's executable. -add_executable (benchsleef128 ${BENCH_SRC_FILE}) +add_executable (benchsleef128 "benchsleef.cpp" ${BENCH_HPP_SRC_FILES}) set_target_properties(benchsleef128 PROPERTIES ${BENCH_PROPERTIES}) target_compile_options(benchsleef128 PRIVATE ${EXTRA_CFLAGS} -march=native) -target_link_libraries(benchsleef128 ${BENCH_LIBS}) +target_link_libraries(benchsleef128 sleef ${GOOGLE_BENCH_LIBS}) add_dependencies(benchsleef128 googlebenchmark) +if(SLEEF_BUILD_BENCH_REF) + add_executable (benchlibm128 "benchlibm.cpp" ${BENCH_HPP_SRC_FILES}) + set_target_properties(benchlibm128 PROPERTIES ${BENCH_PROPERTIES}) + target_compile_options(benchlibm128 PRIVATE ${EXTRA_CFLAGS} -march=native "-DBENCH_LIBM") + target_link_libraries(benchlibm128 ${GOOGLE_BENCH_LIBS}) + add_dependencies(benchlibm128 googlebenchmark) +endif() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") - add_executable (benchsleef256 ${BENCH_SRC_FILE}) + add_executable (benchsleef256 "benchsleef.cpp" ${BENCH_HPP_SRC_FILES}) set_target_properties(benchsleef256 PROPERTIES ${BENCH_PROPERTIES}) target_compile_options(benchsleef256 PRIVATE ${EXTRA_CFLAGS} "-march=native" "-DARCH_VECT_LEN=256") - target_link_libraries(benchsleef256 ${BENCH_LIBS}) + target_link_libraries(benchsleef256 sleef ${GOOGLE_BENCH_LIBS}) add_dependencies(benchsleef256 googlebenchmark) - add_executable (benchsleef512 ${BENCH_SRC_FILE}) + add_executable (benchsleef512 "benchsleef.cpp" ${BENCH_HPP_SRC_FILES}) set_target_properties(benchsleef512 PROPERTIES ${BENCH_PROPERTIES}) target_compile_options(benchsleef512 PRIVATE ${EXTRA_CFLAGS} "-mavx512f" "-DARCH_VECT_LEN=512") - target_link_libraries(benchsleef512 ${BENCH_LIBS}) + target_link_libraries(benchsleef512 sleef ${GOOGLE_BENCH_LIBS}) add_dependencies(benchsleef512 googlebenchmark) endif() \ No newline at end of file diff --git a/src/libm-benchmarks/README.md b/src/libm-benchmarks/README.md index c2aa539e..d91433bd 100644 --- a/src/libm-benchmarks/README.md +++ b/src/libm-benchmarks/README.md @@ -62,6 +62,15 @@ for vector functions respectively. Note these executables can also be used to benchmark scalar functions. +

Benchmarking libm

+This tool can also benchmark libm functions listed in +`benchlibm.cpp`. +To enable this, pass on extra build option `-DSLEEF_BUILD_BENCH_REF=ON` +(on top of `-DSLEEF_BUILD_BENCH` from before). +This will produce a new script `./build/bin/benchlibm128`. +You can interact with this in a similar fashion as described for +`./build/bin/benchsleef128`. +

Maintenance

Some functions are still not enabled in the benchmarks. In order to add a function which uses the types already diff --git a/src/libm-benchmarks/benchlibm.cpp b/src/libm-benchmarks/benchlibm.cpp new file mode 100644 index 00000000..2d29d95b --- /dev/null +++ b/src/libm-benchmarks/benchlibm.cpp @@ -0,0 +1,69 @@ +// Copyright Naoki Shibata and contributors 2024. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "benchmark_callers_libm.hpp" +#include + +// ======================TRIG========================== +// sin on different intervals +BENCH_SCALAR(sin, 0, 6.28); +BENCH_SCALAR(sin, 0, 1e+6); +BENCH_SINGLE_SCALAR(sin, 0, 1e20); +BENCH_DOUBLE_SCALAR(sin, 0, 1e+100); + +// cos on different intervals +BENCH_SCALAR(cos, 0, 6.28); +BENCH_SCALAR(cos, 0, 1e+6); +BENCH_SINGLE_SCALAR(cos, 0, 1e20); +BENCH_DOUBLE_SCALAR(cos, 0, 1e+100); + +// tan on different intervals +BENCH_SCALAR(tan, 0, 6.28); +BENCH_SCALAR(tan, 0, 1e+6); +BENCH_SINGLE_SCALAR(tan, 0, 1e20); +BENCH_DOUBLE_SCALAR(tan, 0, 1e+100); + +BENCH_SCALAR_VOID_3ARGS(sincos, 0, 6.28); +BENCH_SCALAR_VOID_3ARGS(sincos, 0, 1e+6); +BENCH_SINGLE_SCALAR_VOID_3ARGS(sincos, 0, 1e20); +BENCH_DOUBLE_SCALAR_VOID_3ARGS(sincos, 0, 1e+100); + +// inverse trig +BENCH_SCALAR(asin, -1.0, 1.0); +BENCH_SCALAR(acos, -1.0, 1.0); +BENCH_SCALAR(atan, -10, 10); +BENCH_SCALAR_2ARGS(atan2, -10, 10) + +// ======================NON TRIG========================== +// log +BENCH_SINGLE_SCALAR(log, 0, 1e+38); +BENCH_DOUBLE_SCALAR(log, 0, 1e+100); + +BENCH_SINGLE_SCALAR(log2, 0, 1e+38); +BENCH_DOUBLE_SCALAR(log2, 0, 1e+100); + +BENCH_SINGLE_SCALAR(log10, 0, 1e+38); +BENCH_DOUBLE_SCALAR(log10, 0, 1e+100); + +BENCH_SINGLE_SCALAR(log1p, 0, 1e+38); +BENCH_DOUBLE_SCALAR(log1p, 0, 1e+100); + +// exp +BENCH_SINGLE_SCALAR(exp, -700, 700); +BENCH_DOUBLE_SCALAR(exp, -700, 700); + +BENCH_SINGLE_SCALAR(exp2, -100, 100); +BENCH_DOUBLE_SCALAR(exp2, -700, 700); + +BENCH_SINGLE_SCALAR(exp10, -100, 100); +BENCH_DOUBLE_SCALAR(exp10, -700, 700); + +BENCH_SINGLE_SCALAR(expm1, -100, 100); +BENCH_DOUBLE_SCALAR(expm1, -700, 700); + +// pow +BENCH_SCALAR_2ARGS(pow, -30, 30); + +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/src/libm-benchmarks/benchmark_callers_libm.hpp b/src/libm-benchmarks/benchmark_callers_libm.hpp new file mode 100644 index 00000000..1cee4648 --- /dev/null +++ b/src/libm-benchmarks/benchmark_callers_libm.hpp @@ -0,0 +1,46 @@ +// Copyright Naoki Shibata and contributors 2024. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#pragma once +#include "benchmark_templates.hpp" + +// Callers for libm - no separate file as its much simpler +// only interested in scalar (i think?) +#define BENCH(funname, funtype, namefilter, min, max) \ + BENCHMARK_CAPTURE(BM_Sleef_templated_function, #funname, funtype funname, min, max) \ + ->Name("MB_libm_" #funname "_" #namefilter "_" #min "_" #max); + +#define BENCH_SINGLE_SCALAR(fun, min, max) \ + BENCH(fun, (float (*) (float)), u10_scalarf, min, max); +#define BENCH_DOUBLE_SCALAR(fun, min, max) \ + BENCH(fun, (double (*) (double)), u10_scalard, min, max); + +#define BENCH_SCALAR(fun, min, max) \ + BENCH_SINGLE_SCALAR(fun, min, max); \ + BENCH_DOUBLE_SCALAR(fun, min, max); + +// special case for pow and atan2 +#define BENCH_SINGLE_SCALAR_2ARGS(fun, min, max) \ + BENCH(fun, (float (*) (float, float)), u10_scalarf, min, max); +#define BENCH_DOUBLE_SCALAR_2ARGS(fun, min, max) \ + BENCH(fun, (double (*) (double, double)), u10_scalard, min, max); + +#define BENCH_SCALAR_2ARGS(fun, min, max) \ + BENCH_SINGLE_SCALAR_2ARGS(fun, min, max); \ + BENCH_DOUBLE_SCALAR_2ARGS(fun, min, max); + + +// special case for sincos +#define BENCH_SINGLE_SCALAR_VOID_3ARGS(fun, min, max) \ + BENCH(fun, (void (*)(float, float*, float*)), u10_scalarf, min, max); +#define BENCH_DOUBLE_SCALAR_VOID_3ARGS(fun, min, max) \ + BENCH(fun, (void (*)(double, double*, double*)), u10_scalard, min, max); + +#define BENCH_SCALAR_VOID_3ARGS(fun, min, max) \ + BENCH_SINGLE_SCALAR_VOID_3ARGS(fun, min, max); \ + BENCH_DOUBLE_SCALAR_VOID_3ARGS(fun, min, max); + + + diff --git a/src/libm-benchmarks/benchmark_templates.hpp b/src/libm-benchmarks/benchmark_templates.hpp index eaec9747..a314cb32 100644 --- a/src/libm-benchmarks/benchmark_templates.hpp +++ b/src/libm-benchmarks/benchmark_templates.hpp @@ -45,3 +45,19 @@ static void BM_Sleef_templated_function(benchmark::State &state, benchmark::Counter(num_els_processed, benchmark::Counter::kIsRate | benchmark::Counter::kInvert); } + +// Necessary for libm sincos (which takes 3 arguments) +template +static void BM_Sleef_templated_function(benchmark::State &state, + void (*fun)(T, T*, T*), double min, + double max) { + T p0, p1; + T x = gen_input(min, max); + for (auto _ : state) { + call_fun(fun, x, &p0, &p1); + } + int num_els_processed = state.iterations() * vector_len; + state.counters["NSperEl"] = + benchmark::Counter(num_els_processed, benchmark::Counter::kIsRate | + benchmark::Counter::kInvert); +} diff --git a/src/libm-benchmarks/gen_input.hpp b/src/libm-benchmarks/gen_input.hpp index ac3186d8..62391824 100644 --- a/src/libm-benchmarks/gen_input.hpp +++ b/src/libm-benchmarks/gen_input.hpp @@ -6,6 +6,7 @@ #pragma once #include "type_defs.hpp" #include +#include #include /////////////////////////////////// diff --git a/src/libm-benchmarks/type_defs.hpp b/src/libm-benchmarks/type_defs.hpp index bd8af7ea..eb63cddc 100644 --- a/src/libm-benchmarks/type_defs.hpp +++ b/src/libm-benchmarks/type_defs.hpp @@ -4,7 +4,6 @@ // http://www.boost.org/LICENSE_1_0.txt) #pragma once -#include /////////////////////////////////// // Library Includes and /////////// @@ -14,6 +13,9 @@ template const inline int vector_len = 1; template <> const inline int vector_len = 1; template <> const inline int vector_len = 1; +#if !defined(BENCH_LIBM) + +#include #if defined(__i386__) || defined(__x86_64__) #if defined(_MSC_VER) #include @@ -93,4 +95,6 @@ typedef svfloat32x2_t svfloat2; template <> const inline int vector_len = svcntw(); template <> const inline int vector_len = svcntd(); #define ENABLE_SVECTOR_BENCHMARKS +#endif + #endif \ No newline at end of file