Skip to content

Commit

Permalink
Fix strong symbol definitions in Differentiator.h. Add unittests.
Browse files Browse the repository at this point in the history
Fixes: #693, Fixes #314.
  • Loading branch information
vgvassilev committed Jan 3, 2024
1 parent 38e6664 commit 5397d7a
Show file tree
Hide file tree
Showing 16 changed files with 326 additions and 65 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:

include:
- name: osx-clang-runtime11
os: macos-latest
os: macos-11
compiler: clang
clang-runtime: '11'

Expand Down Expand Up @@ -860,7 +860,9 @@ jobs:
lcov --directory . --capture --output-file coverage.info --gcov-tool /usr/bin/gcov-${vers}
# filter out system and extra files.
# To also not include test code in coverage add them with full path to the patterns: '*/tests/*'
lcov --remove coverage.info '/usr/*' "${HOME}"'/.cache/*' "$GITHUB_WORKSPACE"'/test/*' --output-file coverage.info
lcov --remove coverage.info '/usr/*' "${HOME}"'/.cache/*' \
"$GITHUB_WORKSPACE"'/test/*' "$GITHUB_WORKSPACE"'/unittests/*' \
--output-file coverage.info
# output coverage data for debugging (optional)
lcov --list coverage.info
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ if(CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
set(GCC_COVERAGE_LINK_FLAGS "--coverage")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHAREDLINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
set(CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
endif()

##
Expand Down Expand Up @@ -296,6 +296,7 @@ if (CLAD_INCLUDE_DOCS)
endif()

if (NOT CLAD_BUILD_STATIC_ONLY)
add_subdirectory(unittests)
add_subdirectory(test)
add_subdirectory(demos/ErrorEstimation/CustomModel)
add_subdirectory(demos/ErrorEstimation/PrintModel)
Expand Down
99 changes: 69 additions & 30 deletions cmake/modules/AddCladBenchmark.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,106 @@ string(REPLACE "/" "" CURRENT_REPO_COMMIT ${CURRENT_REPO_COMMIT})
set_property(DIRECTORY APPEND PROPERTY
CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/.git/HEAD")


# Change the default compiler to the clang which we run clad upon.
set(CMAKE_CXX_COMPILER ${LLVM_TOOLS_BINARY_DIR}/clang)

#----------------------------------------------------------------------------
# function CB_ADD_GBENCHMARK(<benchmark> source1 source2... LIBRARIES libs)
#----------------------------------------------------------------------------
function(CB_ADD_GBENCHMARK benchmark)
cmake_parse_arguments(ARG "" "LABEL" "DEPENDS;LIBRARIES" ${ARGN})
set(source_files ${ARG_UNPARSED_ARGUMENTS})

add_executable(${benchmark} ${source_files})
#-------------------------------------------------------------------------------
# function ENABLE_CLAD_FOR_EXECUTABLE(<executable>
# DEPENDS dependencies...
# A list of targets that the executable depends on.
# LIBRARIES libraries...
# A list of libraries to be linked in. Defaults to stdc++ pthread m.
# )
#-------------------------------------------------------------------------------
function(ENABLE_CLAD_FOR_EXECUTABLE executable)
if (NOT TARGET ${executable})
message(FATAL_ERROR "'${executable}' is not a valid target.")
endif()

# Add the clad plugin
target_compile_options(${benchmark} PUBLIC -fplugin=$<TARGET_FILE:clad>)
target_compile_options(${executable} PUBLIC -fplugin=$<TARGET_FILE:clad>)

# Debugging. Emitting the derivatives' source code.
#target_compile_options(${benchmark} PUBLIC "SHELL:-Xclang -plugin-arg-clad"
#target_compile_options(${executable} PUBLIC "SHELL:-Xclang -plugin-arg-clad"
# "SHELL: -Xclang -fdump-derived-fn")

# Debugging. Emit llvm IR.
#target_compile_options(${benchmark} PUBLIC -S -emit-llvm)
#target_compile_options(${executable} PUBLIC -S -emit-llvm)

# Debugging. Optimization misses.
#target_compile_options(${benchmark} PUBLIC "SHELL:-Xclang -Rpass-missed=.*inline.*")
#target_compile_options(${executable} PUBLIC "SHELL:-Xclang -Rpass-missed=.*inline.*")

# Clad requires us to link against these libraries.
target_link_libraries(${executable} PUBLIC stdc++ pthread m)

target_include_directories(${executable} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
set_property(TARGET ${executable} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

add_dependencies(${executable} clad)
# If clad.so changes we don't need to relink but to rebuild the source files.
# $<TARGET_FILE:clad> does not work for OBJECT_DEPENDS.
set (CLAD_SO_PATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/clad${CMAKE_SHARED_LIBRARY_SUFFIX}")
set_source_files_properties(${source_files} PROPERTY OBJECT_DEPENDS ${CLAD_SO_PATH})

# Add dependencies to executable
if(ARG_DEPENDS)
add_dependencies(${executable} ${ARG_DEPENDS})
endif(ARG_DEPENDS)

endfunction(ENABLE_CLAD_FOR_EXECUTABLE)

#-------------------------------------------------------------------------------
# function ADD_CLAD_EXECUTABLE(<executable> sources...
# DEPENDS dependencies...
# A list of targets that the executable depends on.
# LIBRARIES libraries...
# A list of libraries to be linked in. Defaults to stdc++ pthread m.
# )
#-------------------------------------------------------------------------------
function(ADD_CLAD_EXECUTABLE executable)
cmake_parse_arguments(ARG "" "DEPENDS;LIBRARIES" "" ${ARGN})

set(source_files ${ARG_UNPARSED_ARGUMENTS})

add_executable(${executable} ${source_files})

ENABLE_CLAD_FOR_EXECUTABLE(${executable} ${ARGN})

endfunction(ADD_CLAD_EXECUTABLE)

#-------------------------------------------------------------------------------
# function CB_ADD_GBENCHMARK(<benchmark> sources
# LABEL <short|long>
# A label that classifies how much time a benchmark is expected to take.
# Short benchmarks time out at 1200 seconds, long at 2400.
# DEPENDS dependencies...
# A list of targets that the executable depends on.
# LIBRARIES libraries...
# A list of libraries to be linked in. Defaults to stdc++ pthread m.
# )
#-------------------------------------------------------------------------------
function(CB_ADD_GBENCHMARK benchmark)
cmake_parse_arguments(ARG "" "LABEL" "" ${ARGN})
ADD_CLAD_EXECUTABLE(${benchmark} ${ARG_UNPARSED_ARGUMENTS})

# Optimize the produced code.
target_compile_options(${benchmark} PUBLIC -O3)

# Turn off numerical diff fallback.
target_compile_definitions(${benchmark} PUBLIC CLAD_NO_NUM_DIFF)

# Clad requires us to link against these libraries.
target_link_libraries(${benchmark} PUBLIC stdc++ pthread m)

target_include_directories(${benchmark} PUBLIC ${CMAKE_CURRENT_BINARY_DIR} ${GBENCHMARK_INCLUDE_DIR})
set_property(TARGET ${benchmark} PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

target_link_libraries(${benchmark} PUBLIC ${ARG_LIBRARIES} gbenchmark)
if (NOT APPLE)
target_link_libraries(${benchmark} PUBLIC rt)
endif()

add_dependencies(${benchmark} clad)
# If clad.so changes we don't need to relink but to rebuild the source files.
# $<TARGET_FILE:clad> does not work for OBJECT_DEPENDS.
set (CLAD_SO_PATH "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/clad${CMAKE_SHARED_LIBRARY_SUFFIX}")
set_source_files_properties(${source_files} PROPERTY OBJECT_DEPENDS ${CLAD_SO_PATH})

set (TIMEOUT_VALUE 1200)
set (LABEL "short")
if (ARG_LABEL AND "${ARG_LABEL}" STREQUAL "long")
set (TIMEOUT_VALUE 2400)
set (LABEL "long")
endif()

# Add dependencies to benchmark
if(ARG_DEPENDS)
add_dependencies(${benchmark} ${ARG_DEPENDS})
endif()

# Add benchmark as a CTest
add_test(NAME clad-${benchmark}
COMMAND ${benchmark} --benchmark_out_format=json
Expand Down
94 changes: 94 additions & 0 deletions cmake/modules/CladGoogleTest.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
set(_gtest_byproduct_binary_dir
${CMAKE_BINARY_DIR}/downloads/googletest-prefix/src/googletest-build)
set(_gtest_byproducts
${_gtest_byproduct_binary_dir}/lib/libgtest.a
${_gtest_byproduct_binary_dir}/lib/libgtest_main.a
${_gtest_byproduct_binary_dir}/lib/libgmock.a
${_gtest_byproduct_binary_dir}/lib/libgmock_main.a
)

if(MSVC)
set(EXTRA_GTEST_OPTS
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=${_gtest_byproduct_binary_dir}/lib/
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL:PATH=${_gtest_byproduct_binary_dir}/lib/
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=${_gtest_byproduct_binary_dir}/lib/
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO:PATH=${_gtest_byproduct_binary_dir}/lib/
-Dgtest_force_shared_crt=ON
BUILD_COMMAND ${CMAKE_COMMAND} --build <BINARY_DIR> --config Release)
elseif(APPLE)
set(EXTRA_GTEST_OPTS -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT})
endif()

# Remove the coverage flags when compiling external libraries.
string(REPLACE "${GCC_COVERAGE_COMPILE_FLAGS}" "" CMAKE_CXX_FLAGS_NOCOV "${CMAKE_CXX_FLAGS}")
string(REPLACE "${GCC_COVERAGE_COMPILE_FLAGS}" "" CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS_NOCOV "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}")
string(REPLACE "${GCC_COVERAGE_LINK_FLAGS}" "" CMAKE_EXE_LINKER_FLAGS_NOCOV "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "${GCC_COVERAGE_LINK_FLAGS}" "" CMAKE_SHARED_LINKER_FLAGS_NOCOV "${CMAKE_SHARED_LINKER_FLAGS}")

include(ExternalProject)
ExternalProject_Add(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
EXCLUDE_FROM_ALL 1
GIT_SHALLOW 1
GIT_TAG release-1.12.1
UPDATE_COMMAND ""
# # Force separate output paths for debug and release builds to allow easy
# # identification of correct lib in subsequent TARGET_LINK_LIBRARIES commands
# CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs
# -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs
# -Dgtest_force_shared_crt=ON
CMAKE_ARGS -G ${CMAKE_GENERATOR}
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS_NOCOV}
-DCMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS=${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS_NOCOV}
-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS_NOCOV}
-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS_NOCOV}
-DCMAKE_AR=${CMAKE_AR}
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
${EXTRA_GTEST_OPTS}
# Disable install step
INSTALL_COMMAND ""
BUILD_BYPRODUCTS ${_gtest_byproducts}
# Wrap download, configure and build steps in a script to log output
LOG_DOWNLOAD ON
LOG_CONFIGURE ON
LOG_BUILD ON
TIMEOUT 600
)

# Specify include dirs for gtest and gmock
ExternalProject_Get_Property(googletest source_dir)
set(GTEST_INCLUDE_DIR ${source_dir}/googletest/include)
set(GMOCK_INCLUDE_DIR ${source_dir}/googlemock/include)
# Create the directories. Prevents bug https://gitlab.kitware.com/cmake/cmake/issues/15052
file(MAKE_DIRECTORY ${GTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR})

# Libraries
ExternalProject_Get_Property(googletest binary_dir)
set(_G_LIBRARY_PATH ${binary_dir}/lib/)

# Use gmock_main instead of gtest_main because it initializes gtest as well.
# Note: The libraries are listed in reverse order of their dependancies.
foreach(lib gtest gtest_main gmock gmock_main)
add_library(${lib} IMPORTED STATIC GLOBAL)
set_target_properties(${lib} PROPERTIES
IMPORTED_LOCATION "${_G_LIBRARY_PATH}${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}"
INTERFACE_INCLUDE_DIRECTORIES "${GTEST_INCLUDE_DIR}"
)
add_dependencies(${lib} googletest)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND
${CMAKE_CXX_COMPILER_VERSION} VERSION_GREATER_EQUAL 9)
target_compile_options(${lib} INTERFACE -Wno-deprecated-copy)
endif()
endforeach()
target_include_directories(gtest INTERFACE ${GTEST_INCLUDE_DIR})
target_include_directories(gmock INTERFACE ${GMOCK_INCLUDE_DIR})

set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${_G_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX})
set_property(TARGET gtest_main PROPERTY IMPORTED_LOCATION ${_G_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest_main${CMAKE_STATIC_LIBRARY_SUFFIX})
set_property(TARGET gmock PROPERTY IMPORTED_LOCATION ${_G_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock${CMAKE_STATIC_LIBRARY_SUFFIX})
set_property(TARGET gmock_main PROPERTY IMPORTED_LOCATION ${_G_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}gmock_main${CMAKE_STATIC_LIBRARY_SUFFIX})
20 changes: 18 additions & 2 deletions cmake/modules/GoogleBenchmark.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ include(ExternalProject)
set(GBENCHMARK_PREFIX "${CMAKE_BINARY_DIR}/benchmark/googlebenchmark-prefix")
set(GBENCHMARK_LIBRARY_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX})

# Remove the coverage flags when compiling external libraries.
string(REPLACE "${GCC_COVERAGE_COMPILE_FLAGS}" "" CMAKE_CXX_FLAGS_NOCOV "${CMAKE_CXX_FLAGS}")
string(REPLACE "${GCC_COVERAGE_COMPILE_FLAGS}" "" CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS_NOCOV "${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS}")
string(REPLACE "${GCC_COVERAGE_LINK_FLAGS}" "" CMAKE_EXE_LINKER_FLAGS_NOCOV "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "${GCC_COVERAGE_LINK_FLAGS}" "" CMAKE_SHARED_LINKER_FLAGS_NOCOV "${CMAKE_SHARED_LINKER_FLAGS}")

#---Find and install google benchmark
ExternalProject_Add(
googlebenchmark
GIT_REPOSITORY https://github.com/google/benchmark.git
EXCLUDE_FROM_ALL 1
GIT_SHALLOW 1
GIT_TAG v1.6.0
UPDATE_COMMAND ""
# TIMEOUT 10
Expand All @@ -22,7 +29,10 @@ ExternalProject_Add(
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_CXX_FLAGS=${GBENCHMARK_CMAKE_CXX_FLAGS}
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS_NOCOV}
-DCMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS=${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS_NOCOV}
-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS_NOCOV}
-DCMAKE_SHARED_LINKER_FLAGS=${CMAKE_SHARED_LINKER_FLAGS_NOCOV}
-DBENCHMARK_ENABLE_TESTING=OFF
# Disable install step
INSTALL_COMMAND ""
Expand All @@ -35,12 +45,18 @@ ExternalProject_Add(
# Specify include dirs for googlebenchmark
ExternalProject_Get_Property(googlebenchmark source_dir)
set(GBENCHMARK_INCLUDE_DIR ${source_dir}/include)
# Create the directories. Prevents bug https://gitlab.kitware.com/cmake/cmake/issues/15052
file(MAKE_DIRECTORY ${GBENCHMARK_INCLUDE_DIR})

# Libraries
ExternalProject_Get_Property(googlebenchmark binary_dir)
set(_GBENCH_LIBRARY_PATH ${binary_dir}/)

# Register googlebenchmark
add_library(gbenchmark IMPORTED STATIC GLOBAL)
set_property(TARGET gbenchmark PROPERTY IMPORTED_LOCATION ${_GBENCH_LIBRARY_PATH}/src/libbenchmark.a)
set_target_properties(gbenchmark PROPERTIES
IMPORTED_LOCATION ${_GBENCH_LIBRARY_PATH}/src/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX}
INTERFACE_INCLUDE_DIRECTORIES "${GBENCHMARK_INCLUDE_DIR}"
)
target_include_directories(gbenchmark INTERFACE ${GBENCHMARK_INCLUDE_DIR})
add_dependencies(gbenchmark googlebenchmark)
12 changes: 3 additions & 9 deletions include/clad/Differentiator/CladConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,10 @@ constexpr unsigned GetBitmaskedOpts(unsigned const first, Opts... opts) {
// Define trap function that is a CUDA compatible replacement for
// exit(int code) function
#ifdef __CUDACC__
__device__ void trap(int code) {
asm("trap;");
}
__host__ void trap(int code) {
exit(code);
}
inline __device__ void trap(int code) { asm("trap;"); }
inline __host__ void trap(int code) { exit(code); }
#else
void trap(int code) {
exit(code);
}
inline void trap(int code) { exit(code); }
#endif

#ifdef __CUDACC__
Expand Down
26 changes: 13 additions & 13 deletions include/clad/Differentiator/Differentiator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,20 @@ template <typename T, typename U> struct ValueAndAdjoint {
};

/// \returns the size of a c-style string
CUDA_HOST_DEVICE unsigned int GetLength(const char* code) {
unsigned int count;
const char* code_copy = code;
#ifdef __CUDACC__
count = 0;
while (*code_copy != '\0') {
count++;
code_copy++;
}
#else
count = strlen(code_copy);
#endif
return count;
inline CUDA_HOST_DEVICE unsigned int GetLength(const char* code) {
unsigned int count;
const char* code_copy = code;
#ifdef __CUDACC__
count = 0;
while (*code_copy != '\0') {
count++;
code_copy++;
}
#else
count = strlen(code_copy);
#endif
return count;
}

/// Tape type used for storing values in reverse-mode AD inside loops.
template <typename T>
Expand Down
Loading

0 comments on commit 5397d7a

Please sign in to comment.