Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
dto-test*
libdto.so*
libdto_explicit.so*
build*/
tests/baselines*/
dtoctl
/doc/dtoctl.1
140 changes: 119 additions & 21 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
cmake_minimum_required(VERSION 3.5...3.31)
project(DTO VERSION 1.0 LANGUAGES C)

# Default to RelWithDebInfo when no build type is specified.
# DTO may be built on its own or as part of another project (add_subdirectory
# or FetchContent). As a subproject only the library is built by default, and
# the parent's settings are left alone.
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(DTO_IS_TOP_LEVEL ON)
else()
set(DTO_IS_TOP_LEVEL OFF)
endif()

# Default to RelWithDebInfo when no build type is specified. Only at the top
# level: CMAKE_BUILD_TYPE is the parent's when DTO is a subproject.
# (Skip for multi-config generators, which ignore CMAKE_BUILD_TYPE.)
get_property(_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT _is_multi_config AND NOT CMAKE_BUILD_TYPE)
if(DTO_IS_TOP_LEVEL AND NOT _is_multi_config AND NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
"Choose the type of build" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
Expand Down Expand Up @@ -55,7 +65,10 @@ target_compile_definitions(dto PRIVATE DTO_STATS_SUPPORT)

# Link libraries
set(DTO_STATIC_LIBS "")
set(DTO_DYNAMIC_LIBS dl)
# pthread: stats use thread keys and a sampler thread; before glibc 2.34 these
# are not in libc, so a program that doesn't link libpthread itself would fail
# to load libdto.
set(DTO_DYNAMIC_LIBS dl pthread)

# Handle accel-config support
if(DTO_ACCEL_CONFIG_SUPPORT)
Expand Down Expand Up @@ -124,15 +137,65 @@ if (HAS_WAITPKG)
endforeach()
endif()

# Build dto-test and dto-test-wodto
add_executable(dto-test dto-test.c)
target_link_libraries(dto-test PRIVATE DTO::dto pthread)
# Build dtoctl. By default it preloads the libdto.so installed alongside it,
# found relative to the dtoctl binary so "cmake --install --prefix" still works,
# and falls back to the configured install path. Set DTOCTL_LIBPATH to always
# preload a specific library instead.
set(DTOCTL_LIBPATH "" CACHE FILEPATH
"Path to libdto.so that dtoctl preloads by default (empty: the installed libdto.so)")
add_executable(dtoctl dtoctl.c)
target_compile_definitions(dtoctl PRIVATE DTO_VERSION="${PROJECT_VERSION}")
if(DTOCTL_LIBPATH)
target_compile_definitions(dtoctl PRIVATE LIBDTO_PATH="${DTOCTL_LIBPATH}")
else()
# Not cached, so it follows later changes to CMAKE_INSTALL_PREFIX.
get_filename_component(DTOCTL_LIBDIR "${CMAKE_INSTALL_LIBDIR}" ABSOLUTE
BASE_DIR "${CMAKE_INSTALL_PREFIX}")
get_filename_component(DTOCTL_BINDIR "${CMAKE_INSTALL_BINDIR}" ABSOLUTE
BASE_DIR "${CMAKE_INSTALL_PREFIX}")
file(RELATIVE_PATH DTOCTL_REL_LIBPATH "${DTOCTL_BINDIR}" "${DTOCTL_LIBDIR}/libdto.so")
target_compile_definitions(dtoctl PRIVATE
LIBDTO_PATH="${DTOCTL_LIBDIR}/libdto.so"
LIBDTO_REL_PATH="${DTOCTL_REL_LIBPATH}")
endif()
install(TARGETS dtoctl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})

# dto-stats-report summarizes "dtoctl --stats-run"; dtoctl looks for it next to
# itself first, so copy it beside dtoctl in the build tree too.
configure_file(dto-stats-report ${CMAKE_CURRENT_BINARY_DIR}/dto-stats-report COPYONLY)
install(PROGRAMS dto-stats-report DESTINATION ${CMAKE_INSTALL_BINDIR})

# Build and install the optional section 1 manual.
find_program(PANDOC_EXECUTABLE NAMES pandoc)
if(PANDOC_EXECUTABLE)
set(DTOCTL_MAN_PAGE "${CMAKE_CURRENT_BINARY_DIR}/doc/dtoctl.1")
add_custom_command(
OUTPUT "${DTOCTL_MAN_PAGE}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/doc"
COMMAND "${PANDOC_EXECUTABLE}" --standalone --to=man
"${CMAKE_CURRENT_SOURCE_DIR}/doc/dtoctl.md" -o "${DTOCTL_MAN_PAGE}"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/doc/dtoctl.md"
COMMENT "Generating dtoctl(1) manual"
VERBATIM)
add_custom_target(dtoctl-man ALL DEPENDS "${DTOCTL_MAN_PAGE}")
install(FILES "${DTOCTL_MAN_PAGE}" DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
else()
message(STATUS "Skipping dtoctl manual generation and installation: install pandoc to build the man page.")
endif()

add_executable(dto-test-wodto dto-test.c)
target_link_libraries(dto-test-wodto PRIVATE pthread)
# Build dto-test and dto-test-wodto
option(DTO_BUILD_TEST_APPS "Build the dto-test and dto-test-wodto applications"
${DTO_IS_TOP_LEVEL})
if(DTO_BUILD_TEST_APPS)
add_executable(dto-test dto-test.c)
target_link_libraries(dto-test PRIVATE DTO::dto pthread)

add_executable(dto-test-wodto dto-test.c)
target_link_libraries(dto-test-wodto PRIVATE pthread)
endif()

# ---- Test Suite ----
option(DTO_BUILD_TESTS "Build the DTO test suite" ON)
option(DTO_BUILD_TESTS "Build the DTO test suite" ${DTO_IS_TOP_LEVEL})

if(DTO_BUILD_TESTS)
enable_testing()
Expand All @@ -158,6 +221,41 @@ if(DTO_BUILD_TESTS)
TIMEOUT 120
)
endif()
# dtoctl option handling and environment setup (no DSA hardware needed)
add_test(NAME dtoctl
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_dtoctl.sh
$<TARGET_FILE:dtoctl> $<TARGET_FILE:dto>)
set_tests_properties(dtoctl PROPERTIES
LABELS "functional"
TIMEOUT 60
)
# Stats collection (DTO_COLLECT_STATS): a workload of known calls, checked
# by a Python script. Runs without DSA (everything is counted as CPU).
find_package(Python3 COMPONENTS Interpreter QUIET)
add_executable(dto-test-stats-workload tests/test_stats_workload.c)
target_compile_options(dto-test-stats-workload PRIVATE -fno-builtin)
target_link_libraries(dto-test-stats-workload PRIVATE DTO::dto pthread)
if(Python3_Interpreter_FOUND)
add_test(NAME stats
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_stats.py
$<TARGET_FILE:dto-test-stats-workload> $<TARGET_FILE:dto>)
set_tests_properties(stats PROPERTIES
LABELS "functional"
TIMEOUT 120
)
else()
message(STATUS "stats test: disabled (python3 not found)")
endif()
# dto-stats-report's arithmetic, on made-up runs
if(Python3_Interpreter_FOUND)
add_test(NAME stats-report
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_stats_report.py
${CMAKE_CURRENT_BINARY_DIR}/dto-stats-report)
set_tests_properties(stats-report PROPERTIES
LABELS "functional"
TIMEOUT 60
)
endif()

# ---- A/B performance regression test ----
# The baseline object is compiled from unguarded upstream sources that
Expand All @@ -176,20 +274,20 @@ if(DTO_BUILD_TESTS)
endif()

# Build current dto.c as object file with renamed symbols (cur_memcpy, etc.)
set(PERF_BASELINE_DIR "${CMAKE_BINARY_DIR}/perf_baseline")
set(PERF_BASELINE_DIR "${CMAKE_CURRENT_BINARY_DIR}/perf_baseline")

add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/dto_current.o
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dto_current.o
COMMAND ${CMAKE_C_COMPILER} -c ${PERF_OBJ_CFLAGS}
${CMAKE_SOURCE_DIR}/dto.c
-o ${CMAKE_BINARY_DIR}/dto_current_raw.o
${CMAKE_CURRENT_SOURCE_DIR}/dto.c
-o ${CMAKE_CURRENT_BINARY_DIR}/dto_current_raw.o
COMMAND objcopy --redefine-sym memcpy=cur_memcpy
--redefine-sym memset=cur_memset
--redefine-sym memcmp=cur_memcmp
--redefine-sym memmove=cur_memmove
${CMAKE_BINARY_DIR}/dto_current_raw.o
${CMAKE_BINARY_DIR}/dto_current.o
DEPENDS ${CMAKE_SOURCE_DIR}/dto.c
${CMAKE_CURRENT_BINARY_DIR}/dto_current_raw.o
${CMAKE_CURRENT_BINARY_DIR}/dto_current.o
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dto.c
COMMENT "Building dto_current.o with renamed symbols"
)

Expand All @@ -200,16 +298,16 @@ if(DTO_BUILD_TESTS)
# object is still fresh, and a custom command would never re-run once
# the object exists.
add_custom_target(dto_baseline_build
COMMAND bash ${CMAKE_SOURCE_DIR}/tests/build_baseline.sh
${CMAKE_SOURCE_DIR} ${PERF_BASELINE_DIR} ${CMAKE_C_COMPILER}
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/tests/build_baseline.sh
${CMAKE_CURRENT_SOURCE_DIR} ${PERF_BASELINE_DIR} ${CMAKE_C_COMPILER}
${PERF_OBJ_CFLAGS}
BYPRODUCTS ${PERF_BASELINE_DIR}/dto_baseline.o
COMMENT "Building dto_baseline.o from baseline branch"
)

add_executable(dto-test-perf
tests/test_perf.c
${CMAKE_BINARY_DIR}/dto_current.o
${CMAKE_CURRENT_BINARY_DIR}/dto_current.o
${PERF_BASELINE_DIR}/dto_baseline.o
)
add_dependencies(dto-test-perf dto_baseline_build)
Expand Down Expand Up @@ -241,7 +339,7 @@ if(DTO_BUILD_TESTS)
LABELS "perf"
TIMEOUT 2400
RUN_SERIAL TRUE
ENVIRONMENT "RESULTS_DIR=${CMAKE_BINARY_DIR}/perf_results;${PERF_COMMON_ENV}"
ENVIRONMENT "RESULTS_DIR=${CMAKE_CURRENT_BINARY_DIR}/perf_results;${PERF_COMMON_ENV}"
)

# short sanity variant: memcpy 4k/64k/1m + memset 64k,
Expand All @@ -252,7 +350,7 @@ if(DTO_BUILD_TESTS)
LABELS "perf"
TIMEOUT 120
RUN_SERIAL TRUE
ENVIRONMENT "PERF_SHORT=1;RESULTS_DIR=${CMAKE_BINARY_DIR}/perf_results_sanity;${PERF_COMMON_ENV}"
ENVIRONMENT "PERF_SHORT=1;RESULTS_DIR=${CMAKE_CURRENT_BINARY_DIR}/perf_results_sanity;${PERF_COMMON_ENV}"
)
else()
message(STATUS "perf test: disabled (requires DTO_ACCEL_CONFIG_SUPPORT and "
Expand Down
39 changes: 35 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,21 @@
#
# SPDX-License-Identifier: MIT

all: libdto dto-test-wodto
all: libdto dtoctl dto-test-wodto man

.PHONY: man install-man

DML_LIB_CXX=-D_GNU_SOURCE

# Path to libdto.so that dtoctl prepends to LD_PRELOAD (matches "make install").
DTOCTL_LIBPATH ?= /usr/lib64/libdto.so
PANDOC ?= pandoc
MANDIR ?= /usr/share/man
# Version reported by "dtoctl --version", taken from the CMake project.
DTO_VERSION := $(shell grep -o 'DTO VERSION [0-9.]*' CMakeLists.txt | cut -d' ' -f3)

libdto: dto.c
gcc -shared -fPIC -Wl,-soname,libdto.so dto.c $(DML_LIB_CXX) -DDTO_STATS_SUPPORT -DDTO_ACCEL_CONFIG_SUPPORT -DDTO_NUMA_SUPPORT -o libdto.so.1.0 -laccel-config -ldl -lnuma -mwaitpkg
gcc -shared -fPIC -Wl,-soname,libdto.so dto.c $(DML_LIB_CXX) -DDTO_STATS_SUPPORT -DDTO_ACCEL_CONFIG_SUPPORT -DDTO_NUMA_SUPPORT -o libdto.so.1.0 -laccel-config -ldl -lnuma -lpthread -mwaitpkg

libdto_nostats: dto.c
gcc -shared -fPIC -Wl,-soname,libdto.so dto.c $(DML_LIB_CXX) -DDTO_ACCEL_CONFIG_SUPPORT -DDTO_NUMA_SUPPORT -o libdto.so.1.0 -laccel-config -ldl -lnuma -mwaitpkg
Expand All @@ -16,11 +25,32 @@ libdto_nostats: dto.c
libdto_explicit: dto.c
gcc -shared -fPIC -Wl,-soname,libdto_explicit.so dto.c $(DML_LIB_CXX) -DDTO_NO_LIBC_INTERPOSE -DDTO_ACCEL_CONFIG_SUPPORT -DDTO_NUMA_SUPPORT -o libdto_explicit.so.1.0 -laccel-config -ldl -lnuma -mwaitpkg

install:
dtoctl: dtoctl.c
gcc -O2 -Wall dtoctl.c -DLIBDTO_PATH=\"$(DTOCTL_LIBPATH)\" -DDTO_VERSION=\"$(DTO_VERSION)\" -o dtoctl

man: doc/dtoctl.1

doc/dtoctl.1: doc/dtoctl.md
@if command -v "$(PANDOC)" >/dev/null 2>&1; then \
"$(PANDOC)" --standalone --to=man $< -o $@; \
else \
echo "Skipping dtoctl manual generation: install pandoc to build the man page."; \
fi

install: dtoctl install-man
cp libdto.so.1.0 /usr/lib64/
cp dto.h /usr/include/
ln -sf /usr/lib64/libdto.so.1.0 /usr/lib64/libdto.so.1
ln -sf /usr/lib64/libdto.so.1.0 /usr/lib64/libdto.so
cp dtoctl /usr/bin/
cp dto-stats-report /usr/bin/

install-man: man
@if [ -f doc/dtoctl.1 ]; then \
install -D -m 644 doc/dtoctl.1 "$(MANDIR)/man1/dtoctl.1"; \
else \
echo "Skipping dtoctl manual installation: no generated man page is available."; \
fi

install-local:
ln -sf ./libdto.so.1.0 ./libdto.so.1
Expand All @@ -33,4 +63,5 @@ dto-test-wodto: dto-test.c
gcc -g dto-test.c $(DML_LIB_CXX) -o dto-test-wodto -lpthread

clean:
rm -rf *.o *.so dto-test
rm -rf *.o *.so dto-test dtoctl
rm -f doc/dtoctl.1
Loading
Loading