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 048e43e
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 40 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
125 changes: 96 additions & 29 deletions cmake/modules/AddCladBenchmark.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -10,67 +10,110 @@ 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})
# Add GBenchmark includes
target_include_directories(${executable} PUBLIC ${GBENCHMARK_INCLUDE_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 All @@ -82,3 +125,27 @@ function(CB_ADD_GBENCHMARK benchmark)
RUN_SERIAL TRUE
DEPENDS ${benchmark})
endfunction(CB_ADD_GBENCHMARK)

#-------------------------------------------------------------------------------
# function ADD_CLAD_GTEST(<gtest> 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_GTEST gtest)
ADD_CLAD_EXECUTABLE(${gtest} ${ARGN})

set(gtest_libs gtest gtest_main)
# Clang prior than clang13 (I think) merges both gmock into gtest.
if (TARGET gmock)
list(APPEND gtest_libs gmock gmock_main)
endif()

target_link_libraries(${gtest} PUBLIC ${ARG_LIBRARIES} ${gtest_libs})
if (NOT APPLE)
#target_link_libraries(${gtest} PUBLIC rt)
endif()

endfunction(ADD_CLAD_GTEST)
6 changes: 3 additions & 3 deletions include/clad/Differentiator/CladConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ 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) {
inline __device__ void trap(int code) {
asm("trap;");
}
__host__ void trap(int code) {
inline __host__ void trap(int code) {
exit(code);
}
#else
void trap(int code) {
inline void trap(int code) {
exit(code);
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion include/clad/Differentiator/Differentiator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ template <typename T, typename U> struct ValueAndAdjoint {
};

/// \returns the size of a c-style string
CUDA_HOST_DEVICE unsigned int GetLength(const char* code) {
inline CUDA_HOST_DEVICE unsigned int GetLength(const char* code) {
unsigned int count;
const char* code_copy = code;
#ifdef __CUDACC__
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
4 changes: 4 additions & 0 deletions unittests/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_clad_unittest(DifferentiatorHTests
DifferentiatorH.cpp
MultiIncludeDifferentiatorH.cpp
)
8 changes: 8 additions & 0 deletions unittests/Basic/DifferentiatorH.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "clad/Differentiator/Differentiator.h"

#include "gtest/gtest.h"

TEST(DifferentiatorH, GetLength) {
EXPECT_TRUE(clad::GetLength("") == 1);
EXPECT_TRUE(clad::GetLength("abc") == 3);
}
1 change: 1 addition & 0 deletions unittests/Basic/MultiIncludeDifferentiatorH.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "clad/Differentiator/Differentiator.h"
35 changes: 35 additions & 0 deletions unittests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
add_custom_target(CladUnitTests)
set_target_properties(CladUnitTests PROPERTIES FOLDER "Clang tests")

# LLVM builds (not installed llvm) provides gtest.
if (NOT TARGET gtest)
include(CladGoogleTest)
include(AddCladBenchmark)
endif()

# add_clad_unittest(test_dirname file1.cpp file2.cpp)
#
# Will compile the list of files together and link against clad.
# Produces a binary named 'basename(test_dirname)'.
function(add_clad_unittest test_dirname)
add_unittest(CladUnitTests ${test_dirname} ${ARGN})

# Remove the llvm_gtest_* coming from add_unittest.
get_target_property(GTEST_LINKED_LIBS ${test_dirname} LINK_LIBRARIES)
list(REMOVE_ITEM GTEST_LINKED_LIBS llvm_gtest_main llvm_gtest)
set_property(TARGET ${test_dirname} PROPERTY LINK_LIBRARIES ${GTEST_LINKED_LIBS})

enable_clad_for_executable(${test_dirname})
#target_include_directories(${test_dirname})
set(gtest_libs gtest gtest_main)
# Clang prior than clang13 (I think) merges both gmock into gtest.
if (TARGET gmock)
list(APPEND gtest_libs gmock gmock_main)
endif()

target_link_libraries(${test_dirname} PUBLIC ${gtest_libs})

endfunction()

add_subdirectory(Basic)

0 comments on commit 048e43e

Please sign in to comment.