Add benchmarks, change project structure
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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
42
bench/CMakeLists.txt
Normal 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
25
bench/include/BH/Bench.h
Normal 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
112
bench/src/Bench.c
Normal 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
33
bench/tests/BenchVec3f.c
Normal 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
75
configure
vendored
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user