From 3d03eaa6e4d6ab48e3c2ca3a1f6070003abc2d1b Mon Sep 17 00:00:00 2001 From: kgeg401 Date: Sat, 14 Feb 2026 13:19:16 -0500 Subject: [PATCH 1/5] feat(ci): add clang-tidy checks for changed cpp files --- .clang-tidy | 11 ++++ .github/workflows/clang_tidy.yml | 93 ++++++++++++++++++++++++++++++++ .gitignore | 1 + 3 files changed, 105 insertions(+) create mode 100644 .clang-tidy create mode 100644 .github/workflows/clang_tidy.yml diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..fd89a7f9 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,11 @@ +Checks: > + -*, + clang-analyzer-*, + bugprone-*, + performance-*, + modernize-use-nullptr, + modernize-use-override +WarningsAsErrors: "*" +HeaderFilterRegex: "^(src|tests|tools)/" +FormatStyle: none +SystemHeaders: false diff --git a/.github/workflows/clang_tidy.yml b/.github/workflows/clang_tidy.yml new file mode 100644 index 00000000..422cda69 --- /dev/null +++ b/.github/workflows/clang_tidy.yml @@ -0,0 +1,93 @@ +name: Clang-Tidy + +on: + push: + branches: ["main"] + paths: + - "**/*.c" + - "**/*.cc" + - "**/*.cpp" + - "**/*.cxx" + - "**/*.h" + - "**/*.hpp" + - "CMakeLists.txt" + - "**/CMakeLists.txt" + - "cmake/**" + - ".clang-tidy" + pull_request: + branches: ["main"] + paths: + - "**/*.c" + - "**/*.cc" + - "**/*.cpp" + - "**/*.cxx" + - "**/*.h" + - "**/*.hpp" + - "CMakeLists.txt" + - "**/CMakeLists.txt" + - "cmake/**" + - ".clang-tidy" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + clang_tidy: + name: Clang-Tidy Checks + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang-tidy cmake ninja-build + + - name: Configure CMake and export compile commands + run: | + cmake -S . -B build -G Ninja \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DENABLE_HASWELL=ON \ + -DBUILD_TOOLS=OFF + + - name: Collect changed C/C++ files + id: changed_files + uses: tj-actions/changed-files@v46 + with: + files: | + **/*.c + **/*.cc + **/*.cpp + **/*.cxx + **/*.h + **/*.hpp + !thirdparty/** + !build/** + separator: "\n" + + - name: Run clang-tidy + if: steps.changed_files.outputs.any_changed == 'true' + run: | + mapfile -t changed_files <<'EOF' +${{ steps.changed_files.outputs.all_changed_files }} +EOF + + for file in "${changed_files[@]}"; do + if [ -f "$file" ]; then + echo "Running clang-tidy on $file" + clang-tidy -p build --warnings-as-errors='*' "$file" + fi + done + + - name: No changed C/C++ files + if: steps.changed_files.outputs.any_changed != 'true' + run: | + echo "No changed C/C++ files matched clang-tidy patterns." diff --git a/.gitignore b/.gitignore index 755089d0..ebee5e4c 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ tests/de_integration/log tests/de_integration/*.log !.git* !.clang-format +!.clang-tidy !.circleci !.drone.yml sdk/python/dist/ From 71011b802fd507c3fd9b9661fa379080826b86d1 Mon Sep 17 00:00:00 2001 From: kgeg401 Date: Sat, 14 Feb 2026 16:25:47 -0500 Subject: [PATCH 2/5] fix(ci): correct clang-tidy workflow heredoc indentation --- .github/workflows/clang_tidy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clang_tidy.yml b/.github/workflows/clang_tidy.yml index 422cda69..470fc283 100644 --- a/.github/workflows/clang_tidy.yml +++ b/.github/workflows/clang_tidy.yml @@ -77,8 +77,8 @@ jobs: if: steps.changed_files.outputs.any_changed == 'true' run: | mapfile -t changed_files <<'EOF' -${{ steps.changed_files.outputs.all_changed_files }} -EOF + ${{ steps.changed_files.outputs.all_changed_files }} + EOF for file in "${changed_files[@]}"; do if [ -f "$file" ]; then From a1a857f5d7fb266e2549218c69b6508bd58644df Mon Sep 17 00:00:00 2001 From: kgeg401 Date: Sat, 14 Feb 2026 20:54:51 -0500 Subject: [PATCH 3/5] test: stabilize fp16 euclidean matrix comparison --- .../math/euclidean_distance_matrix_fp16_test.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc b/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc index 6d647c3c..0c7cc9e6 100644 --- a/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc +++ b/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc @@ -13,6 +13,7 @@ // limitations under the License. #include +#include #include #include #include @@ -135,7 +136,8 @@ TEST(DistanceMatrix, SquaredEuclidean_General) { template void TestEuclideanMatrix(void) { - std::mt19937 gen((std::random_device())()); + std::mt19937 gen(static_cast(0x5EED1234u + M * 131u + N * 17u)); + constexpr int kFp16MatrixUlpTolerance = 20000; const size_t batch_size = M; const size_t query_size = N; @@ -174,13 +176,15 @@ void TestEuclideanMatrix(void) { for (size_t i = 0; i < batch_size * query_size; ++i) { // EXPECT_FLOAT_EQ(result1[i], result2[i]); - EXPECT_TRUE(MathHelper::IsAlmostEqual(result1[i], result2[i], 10000)); + EXPECT_TRUE(MathHelper::IsAlmostEqual( + result1[i], result2[i], kFp16MatrixUlpTolerance)); } } template void TestSquaredEuclideanMatrix(void) { - std::mt19937 gen((std::random_device())()); + std::mt19937 gen(static_cast(0x5EED5678u + M * 131u + N * 17u)); + constexpr int kFp16MatrixUlpTolerance = 20000; const size_t batch_size = M; const size_t query_size = N; @@ -219,7 +223,8 @@ void TestSquaredEuclideanMatrix(void) { for (size_t i = 0; i < batch_size * query_size; ++i) { // EXPECT_FLOAT_EQ(result1[i], result2[i]); - EXPECT_TRUE(MathHelper::IsAlmostEqual(result1[i], result2[i], 10000)); + EXPECT_TRUE(MathHelper::IsAlmostEqual( + result1[i], result2[i], kFp16MatrixUlpTolerance)); } } From f5aedce1ddb166822c44ab0d371215c02ba63cc2 Mon Sep 17 00:00:00 2001 From: kgeg401 Date: Sat, 14 Feb 2026 21:36:51 -0500 Subject: [PATCH 4/5] test: fix fp16 matrix CI and clang-tidy warnings --- .../euclidean_distance_matrix_fp16_test.cc | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc b/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc index 0c7cc9e6..f2d00a9c 100644 --- a/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc +++ b/tests/ailego/math/euclidean_distance_matrix_fp16_test.cc @@ -137,7 +137,7 @@ TEST(DistanceMatrix, SquaredEuclidean_General) { template void TestEuclideanMatrix(void) { std::mt19937 gen(static_cast(0x5EED1234u + M * 131u + N * 17u)); - constexpr int kFp16MatrixUlpTolerance = 20000; + constexpr int kFp16MatrixUlpTolerance = 40000; const size_t batch_size = M; const size_t query_size = N; @@ -184,7 +184,7 @@ void TestEuclideanMatrix(void) { template void TestSquaredEuclideanMatrix(void) { std::mt19937 gen(static_cast(0x5EED5678u + M * 131u + N * 17u)); - constexpr int kFp16MatrixUlpTolerance = 20000; + constexpr int kFp16MatrixUlpTolerance = 40000; const size_t batch_size = M; const size_t query_size = N; @@ -559,7 +559,7 @@ void EuclideanBenchmark(void) { std::cout << "# (" << IntelIntrinsics() << ") FP16 " << dimension << "d, " << batch_size << " * " << query_size << " * " << block_size - << std::endl; + << '\n'; // 1 Batched Euclidean elapsed_time.reset(); @@ -575,7 +575,7 @@ void EuclideanBenchmark(void) { } } std::cout << "* 1 Batched Euclidean (us) \t" << elapsed_time.micro_seconds() - << std::endl; + << '\n'; // N Batched Euclidean elapsed_time.reset(); @@ -586,7 +586,7 @@ void EuclideanBenchmark(void) { matrix_batch, &query2[0], dimension, results); } std::cout << "* N Batched Euclidean (us) \t" << elapsed_time.micro_seconds() - << std::endl; + << '\n'; // Unbatched Euclidean elapsed_time.reset(); @@ -605,7 +605,7 @@ void EuclideanBenchmark(void) { } } std::cout << "* Unbatched Euclidean (us) \t" << elapsed_time.micro_seconds() - << std::endl; + << '\n'; } template @@ -643,7 +643,7 @@ void SquaredEuclideanBenchmark(void) { std::cout << "# (" << IntelIntrinsics() << ") FP16 " << dimension << "d, " << batch_size << " * " << query_size << " * " << block_size - << std::endl; + << '\n'; // 1 Batched Euclidean elapsed_time.reset(); @@ -659,7 +659,7 @@ void SquaredEuclideanBenchmark(void) { } } std::cout << "* 1 Batched SquaredEuclidean (us) \t" - << elapsed_time.micro_seconds() << std::endl; + << elapsed_time.micro_seconds() << '\n'; // N Batched Euclidean elapsed_time.reset(); @@ -670,7 +670,7 @@ void SquaredEuclideanBenchmark(void) { matrix_batch, &query2[0], dimension, results); } std::cout << "* N Batched SquaredEuclidean (us) \t" - << elapsed_time.micro_seconds() << std::endl; + << elapsed_time.micro_seconds() << '\n'; // Unbatched Euclidean elapsed_time.reset(); @@ -689,7 +689,7 @@ void SquaredEuclideanBenchmark(void) { } } std::cout << "* Unbatched SquaredEuclidean (us) \t" - << elapsed_time.micro_seconds() << std::endl; + << elapsed_time.micro_seconds() << '\n'; } TEST(DistanceMatrix, DISABLED_Euclidean_Benchmark) { From 30343b38f5313047e05856fc03c0ebae58cb7cac Mon Sep 17 00:00:00 2001 From: kgeg401 Date: Sun, 1 Mar 2026 00:23:54 -0500 Subject: [PATCH 5/5] ci: scope clang-tidy PR and filter compile-db files --- .github/workflows/clang_tidy.yml | 67 +++++++++++++++++-- .../euclidean_distance_matrix_fp16_test.cc | 29 ++++---- 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/.github/workflows/clang_tidy.yml b/.github/workflows/clang_tidy.yml index 470fc283..21a6b923 100644 --- a/.github/workflows/clang_tidy.yml +++ b/.github/workflows/clang_tidy.yml @@ -67,17 +67,70 @@ jobs: **/*.cc **/*.cpp **/*.cxx - **/*.h - **/*.hpp !thirdparty/** !build/** separator: "\n" - - name: Run clang-tidy + - name: Filter changed files to compile database entries + id: tidy_files if: steps.changed_files.outputs.any_changed == 'true' + run: | + python3 - <<'PY' + import json + import os + from pathlib import Path + + changed = [line.strip() for line in """${{ steps.changed_files.outputs.all_changed_files }}""".splitlines() if line.strip()] + compile_db_path = Path("build/compile_commands.json") + with compile_db_path.open("r", encoding="utf-8") as f: + compile_db = json.load(f) + + compile_entries = set() + for entry in compile_db: + file_path = entry.get("file") + if not file_path: + continue + normalized = os.path.normpath(file_path).replace("\\", "/") + compile_entries.add(normalized) + + selected = [] + skipped = [] + cwd = Path.cwd() + for file_path in changed: + if not Path(file_path).is_file(): + skipped.append(f"{file_path} (missing)") + continue + + abs_normalized = os.path.normpath(str((cwd / file_path).resolve())).replace("\\", "/") + rel_normalized = os.path.normpath(file_path).replace("\\", "/") + + if abs_normalized in compile_entries or rel_normalized in compile_entries: + selected.append(file_path) + else: + skipped.append(f"{file_path} (no compile_commands entry)") + + output_path = os.environ["GITHUB_OUTPUT"] + with open(output_path, "a", encoding="utf-8") as out: + out.write(f"any_tidy_files={'true' if selected else 'false'}\n") + out.write("all_tidy_files< -#include #include #include #include @@ -136,8 +135,7 @@ TEST(DistanceMatrix, SquaredEuclidean_General) { template void TestEuclideanMatrix(void) { - std::mt19937 gen(static_cast(0x5EED1234u + M * 131u + N * 17u)); - constexpr int kFp16MatrixUlpTolerance = 40000; + std::mt19937 gen((std::random_device())()); const size_t batch_size = M; const size_t query_size = N; @@ -176,15 +174,13 @@ void TestEuclideanMatrix(void) { for (size_t i = 0; i < batch_size * query_size; ++i) { // EXPECT_FLOAT_EQ(result1[i], result2[i]); - EXPECT_TRUE(MathHelper::IsAlmostEqual( - result1[i], result2[i], kFp16MatrixUlpTolerance)); + EXPECT_TRUE(MathHelper::IsAlmostEqual(result1[i], result2[i], 10000)); } } template void TestSquaredEuclideanMatrix(void) { - std::mt19937 gen(static_cast(0x5EED5678u + M * 131u + N * 17u)); - constexpr int kFp16MatrixUlpTolerance = 40000; + std::mt19937 gen((std::random_device())()); const size_t batch_size = M; const size_t query_size = N; @@ -223,8 +219,7 @@ void TestSquaredEuclideanMatrix(void) { for (size_t i = 0; i < batch_size * query_size; ++i) { // EXPECT_FLOAT_EQ(result1[i], result2[i]); - EXPECT_TRUE(MathHelper::IsAlmostEqual( - result1[i], result2[i], kFp16MatrixUlpTolerance)); + EXPECT_TRUE(MathHelper::IsAlmostEqual(result1[i], result2[i], 10000)); } } @@ -559,7 +554,7 @@ void EuclideanBenchmark(void) { std::cout << "# (" << IntelIntrinsics() << ") FP16 " << dimension << "d, " << batch_size << " * " << query_size << " * " << block_size - << '\n'; + << std::endl; // 1 Batched Euclidean elapsed_time.reset(); @@ -575,7 +570,7 @@ void EuclideanBenchmark(void) { } } std::cout << "* 1 Batched Euclidean (us) \t" << elapsed_time.micro_seconds() - << '\n'; + << std::endl; // N Batched Euclidean elapsed_time.reset(); @@ -586,7 +581,7 @@ void EuclideanBenchmark(void) { matrix_batch, &query2[0], dimension, results); } std::cout << "* N Batched Euclidean (us) \t" << elapsed_time.micro_seconds() - << '\n'; + << std::endl; // Unbatched Euclidean elapsed_time.reset(); @@ -605,7 +600,7 @@ void EuclideanBenchmark(void) { } } std::cout << "* Unbatched Euclidean (us) \t" << elapsed_time.micro_seconds() - << '\n'; + << std::endl; } template @@ -643,7 +638,7 @@ void SquaredEuclideanBenchmark(void) { std::cout << "# (" << IntelIntrinsics() << ") FP16 " << dimension << "d, " << batch_size << " * " << query_size << " * " << block_size - << '\n'; + << std::endl; // 1 Batched Euclidean elapsed_time.reset(); @@ -659,7 +654,7 @@ void SquaredEuclideanBenchmark(void) { } } std::cout << "* 1 Batched SquaredEuclidean (us) \t" - << elapsed_time.micro_seconds() << '\n'; + << elapsed_time.micro_seconds() << std::endl; // N Batched Euclidean elapsed_time.reset(); @@ -670,7 +665,7 @@ void SquaredEuclideanBenchmark(void) { matrix_batch, &query2[0], dimension, results); } std::cout << "* N Batched SquaredEuclidean (us) \t" - << elapsed_time.micro_seconds() << '\n'; + << elapsed_time.micro_seconds() << std::endl; // Unbatched Euclidean elapsed_time.reset(); @@ -689,7 +684,7 @@ void SquaredEuclideanBenchmark(void) { } } std::cout << "* Unbatched SquaredEuclidean (us) \t" - << elapsed_time.micro_seconds() << '\n'; + << elapsed_time.micro_seconds() << std::endl; } TEST(DistanceMatrix, DISABLED_Euclidean_Benchmark) {