Add benchmarks, change project structure

This commit is contained in:
2025-10-12 10:20:09 +03:00
parent b1870bd709
commit 364d3a32ec
45 changed files with 323 additions and 51 deletions

View File

@@ -47,13 +47,15 @@ include(CheckIncludeFile)
include(CheckSymbolExists)
# Unit testing and coverage configuration
set(ENABLE_TESTING ON CACHE BOOL "Enable unit-testing")
set(ENABLE_TESTS ON CACHE BOOL "Enable unit-testing")
set(ENABLE_BENCHMARKS OFF CACHE BOOL "Enable benchmarks")
set(ENABLE_COVERAGE OFF CACHE BOOL "Enable coverage")
set(ENABLE_EXAMPLES ON CACHE BOOL "Enable building examples")
set(ENABLE_LTO ON CACHE BOOL "Enable LTO support")
set(ENABLE_MT ON CACHE BOOL "Enable multithreading support")
set(USE_CLOCK_GETTIME OFF CACHE BOOL "Force use clock gettime")
set(ENABLE_LFS OFF CACHE BOOL "Enable long file support")
set(USE_SHORT_LIMBS OFF CACHE BOOL "Use shorter limbs in big integers")
# Enable IPO/LTO
if(ENABLE_LTO)
@@ -73,7 +75,7 @@ if(ENABLE_MT)
endif()
# Enable testing
if(ENABLE_TESTING)
if(ENABLE_TESTS)
include(CTest)
enable_testing()
endif()
@@ -87,6 +89,10 @@ if(USE_CLOCK_GETTIME)
set(BH_USE_CLOCK_GETTIME TRUE)
endif()
if(USE_SHORT_LIMBS)
set(BH_USE_SHORT_LIMBS)
endif()
# Set library code
file(GLOB BH_SOURCE
@@ -209,11 +215,15 @@ if(ENABLE_COVERAGE)
endif()
# Tests
if(ENABLE_TESTING)
add_subdirectory(unit)
if(ENABLE_TESTS)
add_subdirectory(test)
endif()
if(ENABLE_EXAMPLES)
add_subdirectory(doc/Examples)
endif()
# Benchmarks
if(ENABLE_BENCHMARKS)
add_subdirectory(bench)
endif()

View File

@@ -3,5 +3,6 @@
#cmakedefine BH_USE_CLOCK_GETTIME
#cmakedefine BH_ENABLE_LFS
#cmakedefine BH_USE_SHORT_LIMBS
#endif /* BH_SRC_CONFIG_H */

42
bench/CMakeLists.txt Normal file
View File

@@ -0,0 +1,42 @@
# Project and C standard configuration
project(bhunit LANGUAGES C)
set(CMAKE_C_STANDARD 90)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Disable extensions
set(CMAKE_C_EXTENSIONS OFF)
# Library code
set(BHBENCH_SOURCE
src/Bench.c
)
set(BHBENCH_HEADER
include/BH/Bench.h
)
# Library
add_library(BHBench STATIC ${BHBENCH_SOURCE} ${BHBENCH_HEADER})
target_include_directories(BHBench PUBLIC include)
target_link_libraries(BHBench BHLib)
# Enable testing
include(CTest)
enable_testing()
# Search files
file(GLOB TEST_FILES "tests/*.c")
foreach(TEST_FILENAME ${TEST_FILES})
# Add test
get_filename_component(TEST_NAME ${TEST_FILENAME} NAME_WE)
add_executable("${TEST_NAME}" ${TEST_FILENAME})
target_link_libraries("${TEST_NAME}" BHLib BHBench)
add_test(NAME "${TEST_NAME}" COMMAND "${TEST_NAME}")
# Enable coverage
if(ENABLE_COVERAGE)
target_compile_options("${TEST_NAME}" PRIVATE -coverage)
target_link_options("${TEST_NAME}" PRIVATE -coverage)
endif()
endforeach()

25
bench/include/BH/Bench.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef BH_BENCH_H
#define BH_BENCH_H
typedef struct BH_Bench BH_Bench;
typedef void (*BH_BenchCallback)(BH_Bench *);
#define BH_BENCH_TEST(name) \
static void bench##name(BH_Bench *state)
#define BH_BENCH_ADD(name) \
BH_BenchAdd(#name, bench##name)
void BH_BenchAdd(const char *name,
BH_BenchCallback cb);
int BH_BenchIter(BH_Bench *state);
int BH_BenchRun(void);
#endif /* BH_BENCH_H */

112
bench/src/Bench.c Normal file
View File

@@ -0,0 +1,112 @@
#include <BH/Bench.h>
#include <BH/Timer.h>
#include <stdlib.h>
#include <stdio.h>
struct BH_Bench
{
struct BH_Bench *next;
const char *name;
BH_BenchCallback cb;
int started;
size_t iterations;
};
static BH_Bench *root = NULL;
static BH_Timer *timer = NULL;
static void cleanup(void)
{
BH_Bench *current;
current = root;
while (current)
{
BH_Bench *next = current->next;
free(current);
current = next;
}
}
void BH_BenchAdd(const char *name,
BH_BenchCallback cb)
{
BH_Bench *bench, *current;
/* Allocate and fill new benchmark entry */
bench = malloc(sizeof(*bench));
if (!bench)
return;
bench->next = NULL;
bench->name = name;
bench->cb = cb;
bench->started = 0;
bench->iterations = 0;
/* Append benchmark entry */
current = root;
while (current && current->next)
current = current->next;
if (current)
current->next = bench;
else
root = bench;
}
int BH_BenchIter(BH_Bench *state)
{
if (state->started)
{
int64_t millis;
state->iterations++;
millis = BH_TimerMilliseconds(timer);
if (millis > 1000 && state->iterations > 10)
{
printf("%s\t%f ips\n", state->name, state->iterations / (millis / 1000.0f));
return 0;
}
}
else
{
state->started = 1;
BH_TimerRestart(timer);
}
return 1;
}
int BH_BenchRun(void)
{
BH_Bench *current;
int result = 0;
timer = BH_TimerNew();
if (!timer)
{
printf("ERROR: Can't create timer for benchmarks");
return -1;
}
printf("Running benchmarks...\n");
current = root;
while (current)
{
current->cb(current);
current = current->next;
fflush(stdout);
}
cleanup();
return 0;
}

33
bench/tests/BenchVec3f.c Normal file
View File

@@ -0,0 +1,33 @@
#include <BH/Bench.h>
#include <BH/Math/Vec3f.h>
#include <stdlib.h>
BH_BENCH_TEST(Vec3f)
{
float a[3], b[3];
a[0] = (rand() % 100) / 200.0;
a[1] = (rand() % 100) / 200.0;
a[2] = (rand() % 100) / 200.0;
b[0] = (rand() % 100) / 200.0;
b[1] = (rand() % 100) / 200.0;
b[2] = (rand() % 100) / 200.0;
while (BH_BenchIter(state))
{
BH_Vec3fAdd(a, b, a);
}
}
int main(int argc, char **argv)
{
BH_UNUSED(argc);
BH_UNUSED(argv);
BH_BENCH_ADD(Vec3f);
return BH_BenchRun();
}

75
configure vendored
View File

@@ -11,8 +11,10 @@ enable_shared="no"
enable_mt="yes"
enable_lfs="no"
enable_tests="yes"
enable_benchmarks="no"
enable_pic="yes"
use_clock_gettime="no"
use_short_limbs="no"
arflags=${ARFLAGS:-cr}
cflags=${CFLAGS}
ldflags=${LDFLAGS}
@@ -48,8 +50,12 @@ for option do
--enable-lfs=no) enable_lfs="no" ;;
--enable-tests|--enable-tests=yes) enable_tests="yes" ;;
--enable-tests=no) enable_tests="no" ;;
--enable-benchmarks|--enable-benchmarks=yes) enable_benchmarks="yes" ;;
--enable-benchmarks=no) enable_benchmarks="no" ;;
--use-clock_gettime|--use-clock_gettime=yes) use_clock_gettime="yes" ;;
--use-clock_gettime=no) use_clock_gettime="no" ;;
--use-short-limbs|--use-short-limbs=yes) use_short_limbs="yes" ;;
--use-short-limbs=no) use_short_limbs="no" ;;
--source=*) source_path="${option#--source=}" ;;
--enable-pic|--with-pic=yes) enable_pic="yes" ;;
--enable-pic=no) enable_pic="no" ;;
@@ -83,7 +89,9 @@ Options:
--enable-mt[=yes|no] Enable multithreading support
--enable-lfs[=yes|no] Enable large file support
--enable-tests[=yes|no] Enable unit tests
--enable-benchmarks[=yes|no] Enable benchmarks
--use-clock_gettime[=yes|no] Use of clock_gettime regardless of the support
--use-short-limbs[=yes|no] Use shorter limbs in big integers
EOF
exit 1
fi
@@ -143,7 +151,10 @@ fi
mkdir src src/Platform src/Math src/String 2>/dev/null
mkdir src/Platform/Posix src/Platform/Win32 src/Platform/Dummy 2>/dev/null
if [ "$enable_tests" = "yes" ]; then
mkdir test test/src unit unit/src 2>/dev/null
mkdir test test/src test/tests 2>/dev/null
fi
if [ "$enable_benchmarks" = "yes" ]; then
mkdir bench bench/src bench/tests 2>/dev/null
fi
library=""
@@ -202,12 +213,25 @@ unit=""
add_test() { tests="${tests}${tests:+:}$1"; }
if [ "$enable_tests" = "yes" ]; then
unit="${source_path}unit/src/Unit.c"
for file in "${source_path}"test/src/*.c; do
unit="${source_path}test/src/Unit.c"
for file in "${source_path}"test/tests/*.c; do
add_test "$file"
done
fi
# Benchamarks
btests=""
bench=""
add_bench() { btests="${btests}${btests:+:}$1"; }
if [ "$enable_benchmarks" = "yes" ]; then
bench="${source_path}bench/src/Bench.c"
for file in "${source_path}"bench/tests/*.c; do
add_bench "$file"
done
fi
# Generate Makefile
{
echo "CC=$cc"
@@ -259,7 +283,7 @@ fi
(
unit_obj="${unit#$source_path}"
printf "\n%s: %s\n" "${unit_obj%.c}.o" "$unit"
printf "\t\$(CC) \$(CFLAGS) -I${source_path}unit/include -c -o \$@ %s\n" "$unit"
printf "\t\$(CC) \$(CFLAGS) -I${source_path}test/include -c -o \$@ %s\n" "$unit"
IFS=":";
for item in $tests; do
@@ -268,7 +292,7 @@ fi
printf "\t\$(LD) \$(LDFLAGS) -o \$@ %s %s \$(STATICLIB) \$(LDLIBS)\n" "${object%.c}.o" "${unit_obj%.c}.o"
printf "\n%s: %s\n" "${object%.c}.o" "$item"
printf "\t\$(CC) \$(CFLAGS) -I${source_path}unit/include -c -o \$@ %s\n" "$item"
printf "\t\$(CC) \$(CFLAGS) -I${source_path}test/include -c -o \$@ %s\n" "$item"
done
printf "\ntest: "
@@ -285,6 +309,32 @@ fi
)
fi
# Benchmarks
if [ "$enable_benchmarks" = "yes" ]; then
(
bench_obj="${bench#$source_path}"
printf "\n%s: %s\n" "${bench_obj%.c}.o" "$bench"
printf "\t\$(CC) \$(CFLAGS) -I${source_path}bench/include -c -o \$@ %s\n" "$bench"
IFS=":";
for item in $btests; do
object="${item#$source_path}"
printf "\n%s: %s %s \$(STATICLIB)\n" "${object%.c}${exe_suffix}" "${object%.c}.o" "${bench_obj%.c}.o"
printf "\t\$(LD) \$(LDFLAGS) -o \$@ %s %s \$(STATICLIB) \$(LDLIBS)\n" "${object%.c}.o" "${bench_obj%.c}.o"
printf "\n%s: %s\n" "${object%.c}.o" "$item"
printf "\t\$(CC) \$(CFLAGS) -I${source_path}bench/include -c -o \$@ %s\n" "$item"
done
printf "\nbenchmarks: "
for item in $btests; do
object="${item#$source_path}"
printf "%s " "${object%.c}${exe_suffix}"
done
echo
)
fi
# Clean
printf "\nclean:\n"
printf "\t-rm -f %s\n" "\$(STATICLIB)"
@@ -307,6 +357,16 @@ fi
printf "\t-rm -f %s\n" "${item%.c}${exe_suffix}"
done
fi
if [ "$enable_benchmarks" = "yes" ]; then
bench_obj="${bench#$source_path}"
printf "\t-rm -f %s\n" "${bench_obj%.c}.o"
for item in $btests; do
item="${item#$source_path}"
printf "\t-rm -f %s\n" "${item%.c}.o"
printf "\t-rm -f %s\n" "${item%.c}${exe_suffix}"
done
fi
)
# Install
@@ -347,6 +407,9 @@ fi
if [ "$enable_lfs" = "yes" ]; then
printf "#define BH_ENABLE_LFS\n";
fi
if [ "$use_short_limbs" = "yes" ]; then
printf "#define BH_USE_SHORT_LIMBS\n";
fi
printf "\n#endif /* BH_SRC_CONFIG_H */\n"
} > Config.h
@@ -370,6 +433,8 @@ echo " --- Enabled options --- "
echo "Enable multithreading: $enable_mt"
echo "Enable long file support: $enable_lfs"
echo "Enable tests: $enable_tests"
echo "Enable benchmarks: $enable_benchmarks"
echo "Enable PIC: $enable_pic"
echo "Build shared library: $enable_shared"
echo "Use clock_gettime: $use_clock_gettime"
echo "Use short limbs: $use_short_limbs"

View File

@@ -62,7 +62,7 @@ static void dragonFixup(struct DragonState *state,
state->k = 0;
/* Burger/Dybvig approach */
#ifndef BH_TWEAK_SHORT_BINT
#ifndef BH_USE_SHORT_LIMBS
state->k = mpiClz((f >> 32) & MPI_MASK);
state->k += (state->k == 32) ? (mpiClz(f & MPI_MASK)) : (0);
#else
@@ -174,7 +174,7 @@ static void dragon(double value,
/* Prepare dragon */
f = frexp(value, &e) * ((uint64_t)1 << 53);
#ifndef BH_TWEAK_SHORT_BINT
#ifndef BH_USE_SHORT_LIMBS
state.r.data[0] = f & MPI_MASK;
state.r.data[1] = (f >> 32) & MPI_MASK;
state.r.size = 2;
@@ -710,7 +710,7 @@ double BH_StringToDouble(const char *string,
}
/* Create double from integer and exponent */
#ifndef BH_TWEAK_SHORT_BINT
#ifndef BH_USE_SHORT_LIMBS
f = (tmp[0].data[1] & 0x001FFFFFul);
f = (f << 32) | tmp[0].data[0];
#else

View File

@@ -1,5 +1,5 @@
/* Platform dependant definition */
#ifndef BH_TWEAK_SHORT_BINT
#ifndef BH_USE_SHORT_LIMBS
#define MPI_SIZE 40
#define MPI_TYPE uint32_t
#define MPI_TTYPE uint64_t
@@ -41,7 +41,7 @@ static const uint8_t clzLookup[256] =
};
#ifndef BH_TWEAK_SHORT_BINT
#ifndef BH_USE_SHORT_LIMBS
static const Mpi BInt1 = {1, {0x00000001ul}};
static const Mpi BInt53 = {2, {0x00000000ul, 0x00200000ul}};

View File

@@ -1,13 +1,30 @@
# Project and C standard configuration
project(bhunit LANGUAGES C)
set(CMAKE_C_STANDARD 90)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Disable extensions
set(CMAKE_C_EXTENSIONS OFF)
# Library code
set(BHUNIT_SOURCE
src/Unit.c
)
set(BHUNIT_HEADER
include/BH/Unit.h
)
# Library
add_library(BHUnit STATIC ${BHUNIT_SOURCE} ${BHUNIT_HEADER})
target_include_directories(BHUnit PUBLIC include)
# Enable testing
include(CTest)
enable_testing()
# Search files
file(GLOB TEST_FILES "src/*.c")
file(GLOB TEST_FILES "tests/*.c")
foreach(TEST_FILENAME ${TEST_FILES})
# Add test

View File

@@ -39,26 +39,15 @@ typedef int (*BH_UnitCallback)(void);
static int unit##name(void)
#define BH_UNIT_ADD(name) \
#define BH_UNIT_ADD(name) \
BH_UnitAdd(#name, unit##name)
/**
* Adds unit test \a cb with name \a name for the testing.
*
* \param name Unit test name
* \param cb Unit test function
*/
void BH_UnitAdd(const char *name,
BH_UnitCallback cb);
/**
* Runs unit tests.
*
* \return On success, returns zero.
* \return On failure, returns error code.
*/
int BH_UnitRun(void);
#endif /* BH_UNIT_H */

View File

@@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.10)
# Project and C standard configuration
project(bhunit LANGUAGES C)
set(CMAKE_C_STANDARD 90)
set(CMAKE_C_STANDARD_REQUIRED ON)
# Disable extensions
set(CMAKE_C_EXTENSIONS OFF)
# Library code
set(BHUNIT_SOURCE
src/Unit.c
)
set(BHUNIT_HEADER
include/BH/Unit.h
)
# Library
add_library(BHUnit STATIC ${BHUNIT_SOURCE} ${BHUNIT_HEADER})
target_include_directories(BHUnit PUBLIC include)