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 2, 2024
1 parent fbe246a commit c14576d
Show file tree
Hide file tree
Showing 15 changed files with 302 additions and 61 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
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
85 changes: 85 additions & 0 deletions cmake/modules/CladGoogleTest.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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()

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}
-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})
9 changes: 8 additions & 1 deletion cmake/modules/GoogleBenchmark.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ 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 Down Expand Up @@ -35,12 +36,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
17 changes: 10 additions & 7 deletions include/clad/Differentiator/NumericalDiff.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ namespace numerical_diff {

/// A buffer manager to request for buffer space
/// while forwarding reference/pointer args to the target function.
ManageBufferSpace bufferManager;
inline ManageBufferSpace& getBufferManager() {
static ManageBufferSpace bufMan;
return bufMan;
}

/// The precision to do the numerical differentiation calculations in.
using precision = double;
Expand All @@ -87,7 +90,7 @@ namespace numerical_diff {
/// \param[in] \c h The h to make representable.
///
/// \returns A value of h that does not result in catastrohic cancellation.
precision make_h_representable(precision x, precision h) {
inline precision make_h_representable(precision x, precision h) {
precision xph = x + h;
precision dx = xph - x;

Expand All @@ -104,7 +107,7 @@ namespace numerical_diff {
/// \param[in] \c arg The input argument to adjust and get h for.
///
/// \returns A calculated and adjusted h value.
precision get_h(precision arg) {
inline precision get_h(precision arg) {
// First get a suitable h value, we do all of this in elevated precision
// (default double). Maximum error in h = eps^4/5
precision h = std::pow(11.25 * std::numeric_limits<precision>::epsilon(),
Expand All @@ -126,8 +129,8 @@ namespace numerical_diff {
/// belongs.
/// \param[in] \c arrPos The position of the array element
/// (-1 if parameter is scalar) to which the error belongs.
void printError(precision derivError, precision evalError, unsigned paramPos,
int arrPos = -1) {
inline void printError(precision derivError, precision evalError,
unsigned paramPos, int arrPos = -1) {
if (arrPos != -1)
printf("\nError Report for parameter at position %d and index %d:\n",
paramPos, arrPos);
Expand Down Expand Up @@ -227,7 +230,7 @@ namespace numerical_diff {
// this is required to make sure that we are retuning a deep copy
// that is valid throughout the scope of the central_diff function.
// Temp is system owned.
T* temp = bufferManager.make_buffer_space<T>(n);
T* temp = getBufferManager().make_buffer_space<T>(n);
// deepcopy
for (std::size_t j = 0; j < n; j++) {
temp[j] = arg[j];
Expand Down Expand Up @@ -318,7 +321,7 @@ namespace numerical_diff {

// five-point stencil formula = (4f[x+h, x-h] - f[x+2h, x-2h])/3
_grad[i][j] = 4.0 * xf1 / 3.0 - xf2 / 3.0;
bufferManager.free_buffer();
getBufferManager().free_buffer();
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ configure_lit_site_cfg(
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
)

configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in
${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py
MAIN_CONFIG
${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py
)

option(CLANG_TEST_USE_VG "Run Clang tests under Valgrind" OFF)
if(CLANG_TEST_USE_VG)
set(CLANG_TEST_EXTRA_ARGS ${CLANG_TEST_EXTRA_ARGS} "--vg")
Expand All @@ -44,6 +51,12 @@ set(CLAD_TEST_PARAMS
clad_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
)

# Unit tests
list(APPEND CLAD_TEST_DEPS CladUnitTests)
list(APPEND CLAD_TEST_PARAMS
clad_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg
)

add_custom_target(clad-test-depends DEPENDS ${CLAD_TEST_DEPS})
set_target_properties(clad-test-depends PROPERTIES FOLDER "Clad tests")

Expand Down
Loading

0 comments on commit c14576d

Please sign in to comment.