VTK-m builds with separate function sections to allow smaller binaries

Consumers of VTK-m when enabling of dropping of unused functions
will see VTK-m functions dropped. Previously this didn't happen
as VTK-m didn't build object files with the correct flags for this.

By allowing the linker to remove unused symbols we see a significant
saving the file size of VTK-m tests, examples, and benchmarks.
An OpenMP build of the tests and benchmarks goes from 168MB to
141MB which is roughly a 16% filesize reduction.

Initially I had presumed that these changes would increase link times.
But in measurements the total wall time for compilation of VTK-m has
stayed about the same ( seeing a decrease of 1.5% ). Presumably the
increased computation is offset by the reduction in file writing.
This commit is contained in:
Robert Maynard 2019-09-09 12:31:01 -04:00
parent d7ecf2241a
commit 1bfcce19dd
23 changed files with 118 additions and 22 deletions

@ -41,6 +41,23 @@ target_link_libraries(vtkm_compiler_flags
# setup that we need C++11 support
target_compile_features(vtkm_compiler_flags INTERFACE cxx_std_11)
# setup our static libraries so that a separate ELF section
# is generated for each function. This allows for the linker to
# remove unused sections. This allows for programs that use VTK-m
# to have the smallest binary impact as they can drop any VTK-m symbol
# they don't use.
if(VTKM_COMPILER_IS_MSVC)
target_compile_options(vtkm_compiler_flags INTERFACE /Gy)
if(TARGET vtkm::cuda)
target_compile_options(vtkm_compiler_flags INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler="/Gy">)
endif()
elseif(NOT VTKM_COMPILER_IS_PGI) #can't find an equivalant PGI flag
target_compile_options(vtkm_compiler_flags INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-ffunction-sections>)
if(TARGET vtkm::cuda)
target_compile_options(vtkm_compiler_flags INTERFACE $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=-ffunction-sections>)
endif()
endif()
# Enable large object support so we can have 2^32 addressable sections
if(VTKM_COMPILER_IS_MSVC)
target_compile_options(vtkm_compiler_flags INTERFACE $<$<COMPILE_LANGUAGE:CXX>:/bigobj>)

@ -135,6 +135,36 @@ function(vtkm_get_cuda_flags settings_var)
endif()
endfunction()
#-----------------------------------------------------------------------------
# Add to a target linker flags that allow unused VTK-m functions to be dropped,
# which helps keep binary sizes down. This works as VTK-m is compiled with
# ffunction-sections which allows for the linker to remove unused functions.
# If you are building a program that loads runtime plugins that can call
# VTK-m this most likely shouldn't be used as symbols the plugin expects
# to exist will be removed.
#
# add_library(lib_that_uses_vtkm ...)
# vtkm_add_drop_unused_function_flags(lib_that_uses_vtkm)
# target_link_libraries(lib_that_uses_vtkm PRIVATE vtkm_filter)
#
function(vtkm_add_drop_unused_function_flags uses_vtkm_target)
get_target_property(lib_type ${uses_vtkm_target} TYPE)
if(${lib_type} STREQUAL "SHARED_LIBRARY" OR
${lib_type} STREQUAL "MODULE_LIBRARY" OR
${lib_type} STREQUAL "EXECUTABLE" )
if(APPLE)
#OSX Linker uses a different flag for this
set_property(TARGET ${uses_vtkm_target} APPEND_STRING PROPERTY
LINK_FLAGS " -Wl,-dead_strip")
elseif(VTKM_COMPILER_IS_GNU OR VTKM_COMPILER_IS_CLANG)
set_property(TARGET ${uses_vtkm_target} APPEND_STRING PROPERTY
LINK_FLAGS " -Wl,--gc-sections")
endif()
endif()
endfunction()
#-----------------------------------------------------------------------------
# Add a relevant information to target that wants to use VTK-m.
@ -146,19 +176,32 @@ endfunction()
#
# vtkm_add_target_information(
# target[s]
# [ DROP_UNUSED_SYMBOLS ]
# [ MODIFY_CUDA_FLAGS ]
# [ EXTENDS_VTKM ]
# [ DEVICE_SOURCES <source_list>
# [ DEVICE_SOURCES <source_list> ]
# )
#
# Usage:
# add_library(lib_that_uses_vtkm STATIC a.cxx)
# vtkm_add_target_information(lib_that_uses_vtkm
# DROP_UNUSED_SYMBOLS
# MODIFY_CUDA_FLAGS
# DEVICE_SOURCES a.cxx
# )
# target_link_libraries(lib_that_uses_vtkm PRIVATE vtkm_filter)
#
# DROP_UNUSED_SYMBOLS: If enabled will apply the appropiate link
# flags to drop unused VTK-m symbols. This works as VTK-m is compiled with
# -ffunction-sections which allows for the linker to remove unused functions.
# If you are building a program that loads runtime plugins that can call
# VTK-m this most likely shouldn't be used as symbols the plugin expects
# to exist will be removed.
# Enabling this will help keep library sizes down when using static builds
# of VTK-m as only the functions you call will be kept. This can have a
# dramatic impact on the size of the resulting executable / shared library.
#
#
# MODIFY_CUDA_FLAGS: If enabled will add the required -arch=<ver> flags
# that VTK-m was compiled with. If you have multiple libraries that use
# VTK-m calling `vtkm_add_target_information` multiple times with
@ -196,7 +239,7 @@ endfunction()
#
#
function(vtkm_add_target_information uses_vtkm_target)
set(options MODIFY_CUDA_FLAGS EXTENDS_VTKM)
set(options DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS EXTENDS_VTKM)
set(multiValueArgs DEVICE_SOURCES)
cmake_parse_arguments(VTKm_TI
"${options}" "${oneValueArgs}" "${multiValueArgs}"
@ -220,6 +263,12 @@ function(vtkm_add_target_information uses_vtkm_target)
set_target_properties(${targets} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${targets} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)
if(VTKm_TI_DROP_UNUSED_SYMBOLS)
foreach(target IN LISTS targets)
vtkm_add_drop_unused_function_flags(${target})
endforeach()
endif()
# Validate that following:
# - We are building with CUDA enabled.
# - We are building a VTK-m library or a library that wants cross library

@ -111,8 +111,10 @@ function(vtkm_unit_tests)
create_test_sourcelist(test_sources ${test_prog}.cxx ${VTKm_UT_SOURCES} ${extraArgs})
add_executable(${test_prog} ${test_prog}.cxx ${VTKm_UT_SOURCES})
vtkm_add_drop_unused_function_flags(${test_prog})
target_compile_definitions(${test_prog} PRIVATE ${VTKm_UT_DEFINES})
#if all backends are enabled, we can use cuda compiler to handle all possible backends.
set(device_sources )
if(TARGET vtkm::cuda AND enable_all_backends)

@ -19,12 +19,15 @@ function(add_benchmark)
add_executable(${exe_name} ${VTKm_AB_FILE})
target_link_libraries(${exe_name} PRIVATE ${VTKm_AB_LIBS})
vtkm_add_drop_unused_function_flags(${exe_name})
vtkm_add_target_information(${exe_name})
set_target_properties(${exe_name} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${VTKm_EXECUTABLE_OUTPUT_PATH}
CXX_VISIBILITY_PRESET "hidden"
CUDA_VISIBILITY_PRESET "hidden"
CUDA_SEPARABLE_COMPILATION ON
)
vtkm_add_target_information(${exe_name} DEVICE_SOURCES ${VTKm_AB_FILE})
endfunction()

@ -8,9 +8,10 @@ compilation units compile correctly.
```cmake
vtkm_add_target_information(
target[s]
[ DROP_UNUSED_SYMBOLS ]
[ MODIFY_CUDA_FLAGS ]
[ EXTENDS_VTKM ]
[ DEVICE_SOURCES <source_list>
[ DEVICE_SOURCES <source_list> ]
)
```
Usage:
@ -25,6 +26,15 @@ compilation units compile correctly.
## Options to vtkm_add_target_information
- DROP_UNUSED_SYMBOLS: If enabled will apply the appropiate link
flags to drop unused VTK-m symbols. This works as VTK-m is compiled with
-ffunction-sections which allows for the linker to remove unused functions.
If you are building a program that loads runtime plugins that can call
VTK-m this most likely shouldn't be used as symbols the plugin expects
to exist will be removed.
Enabling this will help keep library sizes down when using static builds
of VTK-m as only the functions you call will be kept. This can have a
dramatic impact on the size of the resulting executable / shared library.
- MODIFY_CUDA_FLAGS: If enabled will add the required -arch=<ver> flags
that VTK-m was compiled with. If you have multiple libraries that use
VTK-m calling `vtkm_add_target_information` multiple times with
@ -56,3 +66,15 @@ compilation units compile correctly.
to use in filters/worklets. This is only supported when CUDA isn't enabled. Otherwise we need to ERROR!
For most consumers they can ignore the `EXTENDS_VTKM` property as the default will be correct.
The `vtkm_add_target_information` higher order function leverages the `vtkm_add_drop_unused_function_flags` and
`vtkm_get_cuda_flags` functions which can be used by VTK-m consuming applications.
The `vtkm_add_drop_unused_function_flags` function implements all the behavior of `DROP_UNUSED_SYMBOLS` for a single
target.
The `vtkm_get_cuda_flags` function implements a general form of `MODIFY_CUDA_FLAGS` but instead of modiyfing
the `CMAKE_CUDA_FLAGS` it will add the flags to any variable passed to it.

@ -17,5 +17,5 @@ add_executable(Clipping Clipping.cxx)
target_link_libraries(Clipping PRIVATE vtkm_filter)
vtkm_add_target_information(Clipping
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Clipping.cxx)

@ -20,6 +20,7 @@ add_executable(ContourTreeMesh3D ContourTreeMesh3D.cxx)
target_link_libraries(ContourTreeMesh3D vtkm_filter)
vtkm_add_target_information(ContourTreeMesh2D ContourTreeMesh3D
DROP_UNUSED_SYMBOLS
MODIFY_CUDA_FLAGS
DEVICE_SOURCES
ContourTreeMesh2D.cxx ContourTreeMesh3D.cxx)

@ -57,7 +57,7 @@ find_package(VTKm REQUIRED QUIET)
add_executable(ContourTree ContourTreeApp.cxx)
target_link_libraries(ContourTree vtkm_filter)
vtkm_add_target_information(ContourTree
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES ContourTreeApp.cxx)
####################################

@ -19,6 +19,7 @@ target_link_libraries(CosmoCenterFinder PRIVATE vtkm_filter)
target_link_libraries(CosmoHaloFinder PRIVATE vtkm_filter)
vtkm_add_target_information(CosmoCenterFinder CosmoHaloFinder
DROP_UNUSED_SYMBOLS
MODIFY_CUDA_FLAGS
DEVICE_SOURCES
CosmoCenterFinder.cxx CosmoHaloFinder.cxx)

@ -17,6 +17,6 @@ if(TARGET vtkm_rendering)
add_executable(Demo Demo.cxx)
target_link_libraries(Demo PRIVATE vtkm_rendering)
vtkm_add_target_information(Demo
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Demo.cxx)
endif()

@ -21,6 +21,6 @@ if(TARGET OpenGL::GL AND
add_executable(GameOfLife GameOfLife.cxx LoadShaders.h)
target_link_libraries(GameOfLife PRIVATE vtkm_filter OpenGL::GL GLEW::GLEW GLUT::GLUT)
vtkm_add_target_information(GameOfLife
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES GameOfLife.cxx)
endif()

@ -17,5 +17,5 @@ add_executable(HelloWorklet HelloWorklet.cxx)
target_link_libraries(HelloWorklet PRIVATE vtkm_filter)
vtkm_add_target_information(HelloWorklet
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES HelloWorklet.cxx)

@ -16,6 +16,6 @@ if (VTKm_ENABLE_MPI)
add_executable(Histogram Histogram.cxx HistogramMPI.h HistogramMPI.hxx)
target_link_libraries(Histogram PRIVATE vtkm_filter)
vtkm_add_target_information(Histogram
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Histogram.cxx)
endif()

@ -15,5 +15,5 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Lagrangian lagrangian.cxx ABCfield.h)
target_link_libraries(Lagrangian PRIVATE vtkm_filter)
vtkm_add_target_information(Lagrangian
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES lagrangian.cxx)

@ -18,7 +18,7 @@ find_package(VTKm REQUIRED QUIET)
add_executable(ftle LagrangianStructures.cxx)
target_link_libraries(ftle PRIVATE vtkm_cont vtkm_worklet)
vtkm_add_target_information(ftle
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES LagrangianStructures.cxx)
if(TARGET vtkm::tbb)
target_compile_definitions(ftle PRIVATE BUILDING_TBB_VERSION)

@ -33,5 +33,5 @@ if(TARGET vtkm::tbb)
endif()
vtkm_add_target_information(MeshQuality
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES MeshQuality.cxx)

@ -29,5 +29,5 @@ set(srcs
add_executable(MultiBackend ${srcs} ${headers})
target_link_libraries(MultiBackend PRIVATE vtkm_filter Threads::Threads)
vtkm_add_target_information(MultiBackend
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES ${srcs})

@ -16,5 +16,5 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Oscillator Oscillator.cxx)
target_link_libraries(Oscillator PRIVATE vtkm_filter)
vtkm_add_target_information(Oscillator
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES Oscillator.cxx)

@ -16,7 +16,7 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Particle_Advection ParticleAdvection.cxx)
target_link_libraries(Particle_Advection PRIVATE vtkm_filter)
vtkm_add_target_information(Particle_Advection
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES ParticleAdvection.cxx)
if(TARGET vtkm::tbb)
target_compile_definitions(Particle_Advection PRIVATE BUILDING_TBB_VERSION)

@ -13,8 +13,8 @@ project(PolyLineArchimedeanHelix CXX)
find_package(VTKm REQUIRED QUIET)
if (VTKm_ENABLE_RENDERING)
add_executable(PolyLineArchimedeanHelix PolyLineArchimedeanHelix.cxx)
if(TARGET vtkm::cuda)
set_source_files_properties(PolyLineArchimedeanHelix.cxx PROPERTIES LANGUAGE "CUDA")
endif()
target_link_libraries(PolyLineArchimedeanHelix PRIVATE vtkm_filter vtkm_cont vtkm_rendering)
vtkm_add_target_information(PolyLineArchimedeanHelix
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES PolyLineArchimedeanHelix.cxx)
target_link_libraries(PolyLineArchimedeanHelix PRIVATE vtkm_filter vtkm_rendering)
endif()

@ -15,5 +15,5 @@ find_package(VTKm REQUIRED QUIET)
add_executable(RedistributePoints RedistributePoints.cxx RedistributePoints.h)
target_link_libraries(RedistributePoints PRIVATE vtkm_filter)
vtkm_add_target_information(RedistributePoints
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES RedistributePoints.cxx)

@ -17,6 +17,6 @@ find_package(VTKm REQUIRED QUIET)
add_executable(Temporal_Advection TemporalAdvection.cxx)
vtkm_add_target_information(Temporal_Advection
MODIFY_CUDA_FLAGS
DROP_UNUSED_SYMBOLS MODIFY_CUDA_FLAGS
DEVICE_SOURCES TemporalAdvection.cxx)
target_link_libraries(Temporal_Advection PRIVATE vtkm_filter)

@ -20,6 +20,7 @@ add_executable(Triangulate Triangulate.cxx)
target_link_libraries(Triangulate PRIVATE vtkm_filter)
vtkm_add_target_information(Tetrahedralize Triangulate
DROP_UNUSED_SYMBOLS
MODIFY_CUDA_FLAGS
DEVICE_SOURCES
Tetrahedralize.cxx Triangulate.cxx)