diff --git a/CMakeLists.txt b/CMakeLists.txt index 335901d1f..3e9747575 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,8 @@ option(EXPERIMENTAL_SHA256 "Enable experimental SHA256 support (for R&D/test # Optional subsystems option(BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) -option(BUILD_TESTS "Build Tests using the Clar suite" ON) +option(BUILD_TESTS "Build the test suite" ON) +option(BUILD_BENCHMARKS "Build the benchmark suite" OFF) option(BUILD_CLI "Build the command-line interface" ON) option(BUILD_EXAMPLES "Build library usage example apps" OFF) option(BUILD_FUZZERS "Build the fuzz targets" OFF) @@ -112,6 +113,10 @@ if(BUILD_TESTS) add_subdirectory(tests) endif() +if(BUILD_BENCHMARKS) + add_subdirectory(benchmarks) +endif() + if(BUILD_EXAMPLES) add_subdirectory(examples) endif() diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 000000000..1b31354e5 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(libgit2) diff --git a/benchmarks/libgit2/CMakeLists.txt b/benchmarks/libgit2/CMakeLists.txt new file mode 100644 index 000000000..e2668b25e --- /dev/null +++ b/benchmarks/libgit2/CMakeLists.txt @@ -0,0 +1,78 @@ +# util: the unit tests for libgit2's utility library + +if(NOT "${CMAKE_VERSION}" VERSION_LESS 3.27) + cmake_policy(SET CMP0148 OLD) +endif() + +set(Python_ADDITIONAL_VERSIONS 3 2.7) +find_package(PythonInterp) + +if(NOT PYTHONINTERP_FOUND) + message(FATAL_ERROR "Could not find a python interpeter, which is needed to build the tests. " + "Make sure python is available, or pass -DBUILD_TESTS=OFF to skip building the tests") +endif() + +set(CLAR_PATH "${PROJECT_SOURCE_DIR}/deps/clar") +set(BENCHMARK_PATH "${CMAKE_CURRENT_SOURCE_DIR}") +add_definitions(-DCLAR_TMPDIR=\"libgit2_bench\") +add_definitions(-DCLAR_WIN32_LONGPATHS) +add_definitions(-DCLAR_HAS_REALPATH) +add_definitions(-D_FILE_OFFSET_BITS=64) + +file(GLOB BENCHMARK_SRC *.c *.h) +list(SORT BENCHMARK_SRC) + +set(CLAR_SRC + "${CLAR_PATH}/clar.c" + "${CLAR_PATH}/clar.h" + "${CLAR_PATH}/clar/fixtures.h" + "${CLAR_PATH}/clar/print.h" + "${CLAR_PATH}/clar/summary.h" + "${CLAR_PATH}/clar/sandbox.h" + "${CLAR_PATH}/clar/fs.h") + +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/clar.suite ${CMAKE_CURRENT_BINARY_DIR}/clar_suite.h + COMMAND ${PYTHON_EXECUTABLE} ${CLAR_PATH}/generate.py -p benchmark -o "${CMAKE_CURRENT_BINARY_DIR}" -f . + DEPENDS ${BENCHMARK_SRC} + WORKING_DIRECTORY ${BENCHMARK_PATH} +) + +set_source_files_properties( + ${CLAR_PATH}/clar.c + PROPERTIES OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/clar.suite) + +add_executable(libgit2_benchmarks ${CLAR_SRC} + ${BENCHMARK_SRC} + $ + ${LIBGIT2_DEPENDENCY_OBJECTS}) + +target_link_libraries(libgit2_benchmarks libgit2package ${LIBGIT2_SYSTEM_LIBS}) +if(NOT MSVC_IDE) + target_link_libraries(libgit2_benchmarks m) +endif() + +ide_split_sources(libgit2_benchmarks) + +target_include_directories(libgit2_benchmarks PRIVATE + "${CLAR_PATH}" + "${libgit2_BINARY_DIR}/src/util" + "${libgit2_BINARY_DIR}/include" + "${libgit2_SOURCE_DIR}/src/util" + "${libgit2_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}" + "${LIBGIT2_DEPENDENCY_INCLUDES}" + "${LIBGIT2_SYSTEM_INCLUDES}") + +# +# Old versions of gcc require us to declare our test functions; don't do +# this on newer compilers to avoid unnecessary recompilation. +# +if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) + target_compile_options(libgit2_benchmarks PRIVATE -include "clar_suite.h") +endif() + +if(MSVC_IDE) + set_target_properties(libgit2_benchmarks PROPERTIES COMPILE_FLAGS "/Yuprecompiled.h /FIprecompiled.h") + set_source_files_properties("precompiled.c" COMPILE_FLAGS "/Ycprecompiled.h") +endif() diff --git a/benchmarks/libgit2/main.c b/benchmarks/libgit2/main.c new file mode 100644 index 000000000..a8f680f6d --- /dev/null +++ b/benchmarks/libgit2/main.c @@ -0,0 +1,31 @@ +#include + +#include "clar.h" +#include + +#ifdef _WIN32 +int __cdecl main(int argc, char *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + int res; + + clar_test_set_mode(CL_TEST_BENCHMARK); + clar_test_init(argc, argv); + + res = git_libgit2_init(); + if (res < 0) { + const git_error *err = git_error_last(); + const char *msg = err ? err->message : "unknown failure"; + fprintf(stderr, "failed to init libgit2: %s\n", msg); + return res; + } + + /* Run the test suite */ + res = clar_test_run(); + + clar_test_shutdown(); + + return res; +} diff --git a/benchmarks/libgit2/oid.c b/benchmarks/libgit2/oid.c new file mode 100644 index 000000000..8e5b157e6 --- /dev/null +++ b/benchmarks/libgit2/oid.c @@ -0,0 +1,151 @@ +#include "clar.h" + +#include +#include +#include + +#include + +#define BENCHMARK_OID_COUNT 256 + +static git_oid sha1_one[BENCHMARK_OID_COUNT]; +static git_oid *sha1_two; + +#ifdef GIT_EXPERIMENTAL_SHA256 +static git_oid sha256_one[BENCHMARK_OID_COUNT]; +static git_oid *sha256_two; +#endif + +static void update_data_to_val(git_oid *out, git_oid_t type, uint32_t val) +{ + unsigned char data[GIT_OID_MAX_SIZE] = {0}; + size_t size; + +#ifdef GIT_EXPERIMENTAL_SHA256 + size = (type == GIT_OID_SHA256) ? GIT_OID_SHA256_SIZE : GIT_OID_SHA1_SIZE; +#else + size = GIT_OID_SHA1_SIZE; + + ((void)(type)); +#endif + + memset(data, 0, GIT_OID_MAX_SIZE); + + data[size - 1] = (unsigned char)(val & 0x000000ff); + data[size - 2] = (unsigned char)((val & 0x0000ff00) >> 8); + data[size - 3] = (unsigned char)((val & 0x00ff0000) >> 16); + data[size - 4] = (unsigned char)((val & 0x00ff0000) >> 24); + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_assert(git_oid_from_raw(out, data, type) == 0); +#else + cl_assert(git_oid_fromraw(out, data) == 0); +#endif +} + +void benchmark_oid__initialize(void) +{ + uint32_t accum = 0; + size_t i; + + sha1_two = calloc(BENCHMARK_OID_COUNT, sizeof(git_oid)); + cl_assert(sha1_two != NULL); + +#ifdef GIT_EXPERIMENTAL_SHA256 + sha256_two = calloc(BENCHMARK_OID_COUNT, sizeof(git_oid)); + cl_assert(sha256_two != NULL); +#endif + + for (i = 0; i < BENCHMARK_OID_COUNT; i++) { + update_data_to_val(&sha1_one[i], GIT_OID_SHA1, accum++); + update_data_to_val(&sha1_two[i], GIT_OID_SHA1, accum++); + } + +#ifdef GIT_EXPERIMENTAL_SHA256 + for (i = 0; i < BENCHMARK_OID_COUNT; i++) { + update_data_to_val(&sha256_one[i], GIT_OID_SHA256, accum++); + update_data_to_val(&sha256_two[i], GIT_OID_SHA256, accum++); + } +#endif +} + +void benchmark_oid__reset(void) +{ +} + +void benchmark_oid__cleanup(void) +{ + free(sha1_two); + +#ifdef GIT_EXPERIMENTAL_SHA256 + free(sha256_two); +#endif +} + +void benchmark_oid__cmp_sha1(void) +{ + size_t i, j; + + for (i = 0; i < 1024 * 16; i++) + for (j = 0; j < BENCHMARK_OID_COUNT; j++) + git_oid_cmp(&sha1_one[j], &sha1_two[j]); +} + +void benchmark_oid__cmp_sha256(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + size_t i, j; + + for (i = 0; i < 1024 * 16; i++) + for (j = 0; j < BENCHMARK_OID_COUNT; j++) + git_oid_cmp(&sha256_one[j], &sha256_two[j]); +#else + clar__skip(); +#endif +} + +void benchmark_oid__cpy_sha1(void) +{ + git_oid dest; + size_t i, j; + + for (i = 0; i < 1024 * 16; i++) + for (j = 0; j < BENCHMARK_OID_COUNT; j++) + git_oid_cpy(&dest, &sha1_one[j]); +} + +void benchmark_oid__cpy_sha256(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + git_oid dest; + size_t i, j; + + for (i = 0; i < 1024 * 16; i++) + for (j = 0; j < BENCHMARK_OID_COUNT; j++) + git_oid_cpy(&dest, &sha256_one[j]); +#else + clar__skip(); +#endif +} + +void benchmark_oid__zero_sha1(void) +{ + size_t i, j; + + for (i = 0; i < 1024 * 16; i++) + for (j = 0; j < BENCHMARK_OID_COUNT; j++) + git_oid_is_zero(&sha1_one[j]); +} + +void benchmark_oid__zero_sha256(void) +{ +#ifdef GIT_EXPERIMENTAL_SHA256 + size_t i, j; + + for (i = 0; i < 1024 * 16; i++) + for (j = 0; j < BENCHMARK_OID_COUNT; j++) + git_oid_is_zero(&sha256_one[j]); +#else + clar__skip(); +#endif +} diff --git a/benchmarks/libgit2/precompiled.c b/benchmarks/libgit2/precompiled.c new file mode 100644 index 000000000..5f656a45d --- /dev/null +++ b/benchmarks/libgit2/precompiled.c @@ -0,0 +1 @@ +#include "precompiled.h" diff --git a/benchmarks/libgit2/precompiled.h b/benchmarks/libgit2/precompiled.h new file mode 100644 index 000000000..e6b34738d --- /dev/null +++ b/benchmarks/libgit2/precompiled.h @@ -0,0 +1,2 @@ +#include "git2.h" +#include "clar.h" diff --git a/tests/libgit2/CMakeLists.txt b/tests/libgit2/CMakeLists.txt index f8b80eb32..681635a35 100644 --- a/tests/libgit2/CMakeLists.txt +++ b/tests/libgit2/CMakeLists.txt @@ -10,7 +10,7 @@ find_package(PythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR "Could not find a python interpreter, which is needed to build the tests. " "Make sure python is available, or pass -DBUILD_TESTS=OFF to skip building the tests") -ENDIF() +endif() set(CLAR_PATH "${PROJECT_SOURCE_DIR}/deps/clar") set(CLAR_FIXTURES "${PROJECT_SOURCE_DIR}/tests/resources/") @@ -48,7 +48,11 @@ add_executable(libgit2_tests ${SRC_CLAR} ${SRC_TEST} ${LIBGIT2_OBJECTS}) set_target_properties(libgit2_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) target_include_directories(libgit2_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(libgit2_tests SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) + target_link_libraries(libgit2_tests ${LIBGIT2_SYSTEM_LIBS}) +if(NOT MSVC_IDE) + target_link_libraries(libgit2_tests m) +endif() ide_split_sources(libgit2_tests) diff --git a/tests/util/CMakeLists.txt b/tests/util/CMakeLists.txt index 6b44b85fa..ba861aa1c 100644 --- a/tests/util/CMakeLists.txt +++ b/tests/util/CMakeLists.txt @@ -10,7 +10,7 @@ find_package(PythonInterp) if(NOT PYTHONINTERP_FOUND) message(FATAL_ERROR "Could not find a python interpeter, which is needed to build the tests. " "Make sure python is available, or pass -DBUILD_TESTS=OFF to skip building the tests") -ENDIF() +endif() set(CLAR_PATH "${libgit2_SOURCE_DIR}/deps/clar") set(CLAR_FIXTURES "${libgit2_SOURCE_DIR}/tests/resources/") @@ -48,7 +48,11 @@ set_target_properties(util_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${libgit2_B target_include_directories(util_tests PRIVATE ${TEST_INCLUDES} ${LIBGIT2_INCLUDES} ${LIBGIT2_DEPENDENCY_INCLUDES}) target_include_directories(util_tests SYSTEM PRIVATE ${LIBGIT2_SYSTEM_INCLUDES}) + target_link_libraries(util_tests ${LIBGIT2_SYSTEM_LIBS}) +if(NOT MSVC_IDE) + target_link_libraries(util_tests m) +endif() ide_split_sources(util_tests)