Skip to content

Commit 2a77696

Browse files
ci(profiling): add a clang-tidy check (#15725)
## Description This adds a new check for `clang-tidy` for the Profiling codebase. The goal is to improve the quality of our code over time and make sure we don't introduce platform-specific behaviours or things that we might regret/might bite us later. The check currently **does not** fail on reported warnings because we have a lot of them to fix, but it will come in time :) Current build time is around 8 minutes, which I think is fine since it doesn't block anything. This will improve things: #16379
1 parent 9aa7b9f commit 2a77696

3 files changed

Lines changed: 157 additions & 1 deletion

File tree

.gitlab/native.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,25 @@ include:
2121
echo -e "\e[0Ksection_start:`date +%s`:cargo_test[collapsed=true]\r\e[0Kcargo test"
2222
cargo test --no-fail-fast --locked
2323
echo -e "\e[0Ksection_end:`date +%s`:cargo_test\r\e[0K"
24+
25+
"clang-tidy profiling":
26+
stage: tests
27+
image: registry.ddbuild.io/images/mirror/ubuntu:25.04
28+
tags: ["arch:amd64"]
29+
timeout: 20m
30+
needs: []
31+
before_script:
32+
- apt-get update && apt-get install -y clang clang-tidy clang-tools cmake bc python3 python3-pip python3-venv curl jq
33+
- curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y
34+
- source "$HOME/.cargo/env"
35+
- python3 -m venv /tmp/venv
36+
- source /tmp/venv/bin/activate
37+
- python3 -m pip install setuptools wheel cmake setuptools_rust cython pybind11
38+
script:
39+
- |
40+
echo -e "\e[0Ksection_start:`date +%s`:clang_tidy_build[collapsed=true]\r\e[0Kclang-tidy on profiling C++ code"
41+
export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc)
42+
source /tmp/venv/bin/activate
43+
# Run clang-tidy on profiling C++ code (builds only profiling, skips pip install of full package)
44+
ddtrace/internal/datadog/profiling/run_clang_tidy.sh
45+
echo -e "\e[0Ksection_end:`date +%s`:clang_tidy_build\r\e[0K"

ddtrace/internal/datadog/profiling/build_standalone.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ cmake_args=(
109109
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
110110
-DCMAKE_VERBOSE_MAKEFILE=ON
111111
-DLIB_INSTALL_DIR=$(realpath $MY_DIR)/lib
112-
-DPython3_ROOT_DIR=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('prefix'))")
112+
-DPython3_ROOT_DIR=$(python3 -c "import sys; print(sys.prefix)")
113113
-DNATIVE_EXTENSION_LOCATION=$(realpath $MY_DIR)/../../native
114114
-DEXTENSION_SUFFIX=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))")
115115
)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/usr/bin/env bash
2+
# Run clang-tidy on profiling C++ source files
3+
# This script uses run-clang-tidy for parallelization instead of CMake integration
4+
set -euo pipefail
5+
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
8+
BUILD_DIR="${SCRIPT_DIR}/build"
9+
10+
echo "Script dir: ${SCRIPT_DIR}"
11+
echo "Repo root: ${REPO_ROOT}"
12+
13+
# Build the rust native library first (required for cmake to find it)
14+
echo "Building rust native library..."
15+
pushd "${REPO_ROOT}"
16+
pip install setuptools_rust
17+
python3 setup.py build_rust --inplace
18+
popd
19+
20+
# Configure cmake for dd_wrapper to generate compile_commands.json
21+
echo "Configuring cmake for dd_wrapper..."
22+
mkdir -p "${BUILD_DIR}/dd_wrapper"
23+
pushd "${BUILD_DIR}/dd_wrapper"
24+
cmake \
25+
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
26+
-DCMAKE_BUILD_TYPE=Debug \
27+
-DPython3_ROOT_DIR=$(python3 -c "import sys; print(sys.prefix)") \
28+
-DEXTENSION_SUFFIX=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))") \
29+
-DNATIVE_EXTENSION_LOCATION="${REPO_ROOT}/ddtrace/internal/native" \
30+
"${SCRIPT_DIR}/dd_wrapper"
31+
popd
32+
33+
# Configure cmake for stack
34+
echo "Configuring cmake for stack..."
35+
mkdir -p "${BUILD_DIR}/stack"
36+
pushd "${BUILD_DIR}/stack"
37+
cmake \
38+
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
39+
-DCMAKE_BUILD_TYPE=Debug \
40+
-DPython3_ROOT_DIR=$(python3 -c "import sys; print(sys.prefix)") \
41+
-DEXTENSION_SUFFIX=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))") \
42+
-DNATIVE_EXTENSION_LOCATION="${REPO_ROOT}/ddtrace/internal/native" \
43+
-DLIB_INSTALL_DIR="${BUILD_DIR}/dd_wrapper" \
44+
"${SCRIPT_DIR}/stack"
45+
popd
46+
47+
# Merge compile_commands.json from all build directories
48+
MERGED_COMPILE_COMMANDS="${BUILD_DIR}/compile_commands.json"
49+
echo "Merging compile_commands.json files..."
50+
COMPILE_COMMANDS_FILES=()
51+
for subdir in dd_wrapper stack ddup; do
52+
if [[ -f "${BUILD_DIR}/${subdir}/compile_commands.json" ]]; then
53+
COMPILE_COMMANDS_FILES+=("${BUILD_DIR}/${subdir}/compile_commands.json")
54+
fi
55+
done
56+
57+
if [[ ${#COMPILE_COMMANDS_FILES[@]} -eq 0 ]]; then
58+
echo "Error: No compile_commands.json files found after cmake configure"
59+
exit 1
60+
fi
61+
62+
# Merge JSON arrays using jq
63+
if [[ ${#COMPILE_COMMANDS_FILES[@]} -eq 1 ]]; then
64+
cp "${COMPILE_COMMANDS_FILES[0]}" "${MERGED_COMPILE_COMMANDS}"
65+
else
66+
jq -s 'add' "${COMPILE_COMMANDS_FILES[@]}" > "${MERGED_COMPILE_COMMANDS}"
67+
fi
68+
69+
echo "Using merged compile_commands.json from: ${BUILD_DIR}"
70+
71+
# Collect all profiling source files (not headers, not test files, not build artifacts)
72+
# Also exclude fuzz sources since BUILD_FUZZING is OFF by default
73+
SOURCE_FILES=()
74+
while IFS= read -r -d '' file; do
75+
SOURCE_FILES+=("$file")
76+
done < <(find "${SCRIPT_DIR}" \
77+
\( -name "*.cpp" -o -name "*.cc" \) \
78+
! -path "*/build/*" \
79+
! -path "*/CMakeFiles/*" \
80+
! -path "*/test/*" \
81+
! -path "*/fuzz/*" \
82+
! -path "*/_vendor/*" \
83+
-print0)
84+
85+
echo "Found ${#SOURCE_FILES[@]} source files to analyze"
86+
87+
# Clang-tidy checks - focused set for speed
88+
# Exclude checks that are too slow or noisy
89+
CHECKS="bugprone-*,clang-analyzer-*,performance-*,-bugprone-easily-swappable-parameters,-clang-analyzer-security.insecureAPI.*,-performance-avoid-endl"
90+
91+
# Header filter to only analyze our headers, not system headers
92+
HEADER_FILTER="${SCRIPT_DIR}/.*"
93+
94+
# Find run-clang-tidy (may be named differently on different systems)
95+
RUN_CLANG_TIDY=""
96+
for cmd in run-clang-tidy run-clang-tidy-20 run-clang-tidy-19 run-clang-tidy-18; do
97+
if command -v "$cmd" &>/dev/null; then
98+
RUN_CLANG_TIDY="$cmd"
99+
break
100+
fi
101+
done
102+
103+
# Use parallel jobs
104+
JOBS="${CMAKE_BUILD_PARALLEL_LEVEL:-$(nproc)}"
105+
106+
if [[ -n "${RUN_CLANG_TIDY}" ]]; then
107+
echo "Using ${RUN_CLANG_TIDY} with ${JOBS} parallel jobs"
108+
${RUN_CLANG_TIDY} \
109+
-p "${BUILD_DIR}" \
110+
-j "${JOBS}" \
111+
-checks="${CHECKS}" \
112+
-header-filter="${HEADER_FILTER}" \
113+
"${SOURCE_FILES[@]}"
114+
else
115+
echo "run-clang-tidy not found, falling back to sequential clang-tidy"
116+
CLANG_TIDY="${CLANG_TIDY:-clang-tidy}"
117+
FAILED=0
118+
for file in "${SOURCE_FILES[@]}"; do
119+
echo "Analyzing: ${file}"
120+
if ! ${CLANG_TIDY} \
121+
-p "${BUILD_DIR}" \
122+
-checks="${CHECKS}" \
123+
-header-filter="${HEADER_FILTER}" \
124+
"${file}"; then
125+
FAILED=1
126+
fi
127+
done
128+
if [[ ${FAILED} -ne 0 ]]; then
129+
exit 1
130+
fi
131+
fi
132+
133+
echo "clang-tidy analysis complete"
134+

0 commit comments

Comments
 (0)