Skip to content

Commit 1cda667

Browse files
C++ and Python Linting + Formatting + Format checks, including pre-commit and pre-push for GPU-code unit testing + CI (#5)
Part of MET-7 and part of MET-12. In this PR, I have set up C++ and Python linting and formatting using `pixi`. Python format and linting is done using `ruff` while C++ is done using `clang-tools`.We can run them on our own, but they will automatically get triggered via pre-commits hooks anyways. Linting rules could be too strict, so we should feel free to disable warnings that don't make sense. There is also a pre-push hook that runs all the GPU and CPU unit tests (building on top of #2 and #3 ) locally
1 parent 107c206 commit 1cda667

File tree

18 files changed

+1181
-237
lines changed

18 files changed

+1181
-237
lines changed

.clang-format

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
---
2+
Language: Cpp
3+
Standard: c++20
4+
BasedOnStyle: LLVM
5+
IndentWidth: 4
6+
TabWidth: 4
7+
UseTab: Never
8+
ColumnLimit: 100
9+
AccessModifierOffset: -4
10+
AlignAfterOpenBracket: Align
11+
AlignConsecutiveAssignments: false
12+
AlignConsecutiveDeclarations: false
13+
AlignEscapedNewlines: Right
14+
AlignOperands: true
15+
AlignTrailingComments: true
16+
AllowShortBlocksOnASingleLine: false
17+
AllowShortCaseLabelsOnASingleLine: false
18+
AllowShortFunctionsOnASingleLine: Empty
19+
AllowShortIfStatementsOnASingleLine: false
20+
AllowShortLoopsOnASingleLine: false
21+
AlwaysBreakAfterDefinitionReturnType: None
22+
AlwaysBreakAfterReturnType: None
23+
AlwaysBreakBeforeMultilineStrings: false
24+
AlwaysBreakTemplateDeclarations: Yes
25+
BinPackArguments: true
26+
BinPackParameters: true
27+
BraceWrapping:
28+
AfterClass: false
29+
AfterControlStatement: false
30+
AfterEnum: false
31+
AfterFunction: true
32+
AfterNamespace: false
33+
AfterObjCDeclaration: false
34+
AfterStruct: false
35+
AfterUnion: false
36+
AfterExternBlock: false
37+
BeforeCatch: false
38+
BeforeElse: false
39+
IndentBraces: false
40+
SplitEmptyFunction: true
41+
SplitEmptyRecord: true
42+
SplitEmptyNamespace: true
43+
BreakBeforeBinaryOperators: None
44+
BreakBeforeBraces: Attach
45+
BreakBeforeInheritanceComma: false
46+
BreakInheritanceList: BeforeColon
47+
BreakBeforeTernaryOperators: true
48+
BreakConstructorInitializersBeforeComma: false
49+
BreakConstructorInitializers: BeforeColon
50+
BreakAfterJavaFieldAnnotations: false
51+
BreakStringLiterals: true
52+
CommentPragmas: '^ IWYU pragma:'
53+
CompactNamespaces: false
54+
ConstructorInitializerAllOnOneLineOrOnePerLine: false
55+
ConstructorInitializerIndentWidth: 4
56+
ContinuationIndentWidth: 4
57+
Cpp11BracedListStyle: true
58+
DerivePointerAlignment: false
59+
DisableFormat: false
60+
ExperimentalAutoDetectBinPacking: false
61+
FixNamespaceComments: true
62+
ForEachMacros:
63+
- foreach
64+
- Q_FOREACH
65+
- BOOST_FOREACH
66+
IncludeBlocks: Regroup
67+
IncludeCategories:
68+
- Regex: '^<.*\.(cu|cu\.h|cuh|hpp|h)$'
69+
Priority: 1
70+
- Regex: '^<.*\.(cpp|cc|c\+\+|cxx|c)$'
71+
Priority: 2
72+
- Regex: '^<.*'
73+
Priority: 3
74+
- Regex: '.*'
75+
Priority: 4
76+
IncludeIsMainRegex: '(Test)?$'
77+
IndentCaseLabels: true
78+
IndentPPDirectives: None
79+
IndentWrappedFunctionNames: false
80+
JavaScriptQuotes: Leave
81+
JavaScriptWrapImports: true
82+
KeepEmptyLinesAtTheStartOfBlocks: true
83+
MacroBlockBegin: ''
84+
MacroBlockEnd: ''
85+
MaxEmptyLinesToKeep: 1
86+
NamespaceIndentation: None
87+
ObjCBinPackProtocolList: Auto
88+
ObjCBlockIndentWidth: 2
89+
ObjCSpaceAfterProperty: false
90+
ObjCSpaceBeforeProtocolList: true
91+
PenaltyBreakAssignment: 2
92+
PenaltyBreakBeforeFirstCallParameter: 1
93+
PenaltyBreakComment: 300
94+
PenaltyBreakFirstLessLess: 120
95+
PenaltyBreakString: 1000
96+
PenaltyBreakTemplateDeclaration: 10
97+
PenaltyExcessCharacter: 1000000
98+
PenaltyReturnTypeOnItsOwnLine: 200
99+
PointerAlignment: Left
100+
ReflowComments: true
101+
SortIncludes: true
102+
SortUsingDeclarations: true
103+
SpaceAfterCStyleCast: false
104+
SpaceAfterTemplateKeyword: true
105+
SpaceBeforeAssignmentOperators: true
106+
SpaceBeforeParens: ControlStatements
107+
SpaceBeforeRangeBasedForLoopColon: true
108+
SpaceInEmptyParentheses: false
109+
SpacesBeforeTrailingComments: 1
110+
SpacesInAngles: false
111+
SpacesInContainerLiterals: true
112+
SpacesInCStyleCastParentheses: false
113+
SpacesInParentheses: false
114+
SpacesInSquareBrackets: false
115+
StatementMacros:
116+
- Q_UNUSED
117+
- QT_REQUIRE_VERSION
118+
...
119+

.clang-tidy

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
# Clang-tidy configuration for CUDA/C++ project
3+
Checks: >
4+
-*,
5+
bugprone-*,
6+
cert-*,
7+
cppcoreguidelines-*,
8+
performance-*,
9+
readability-*,
10+
modernize-*,
11+
-bugprone-easily-swappable-parameters,
12+
-readability-identifier-length,
13+
-readability-identifier-naming,
14+
-readability-named-parameter,
15+
-readability-implicit-bool-conversion,
16+
-cppcoreguidelines-avoid-magic-numbers,
17+
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
18+
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
19+
-cppcoreguidelines-pro-type-union-access,
20+
-cppcoreguidelines-pro-type-vararg,
21+
-cppcoreguidelines-owning-memory,
22+
-modernize-use-trailing-return-type,
23+
-readability-magic-numbers
24+
25+
WarningsAsErrors: ''
26+
HeaderFilterRegex: '.*'
27+
FormatStyle: 'file'
28+
CheckOptions:
29+
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
30+
value: true
31+
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
32+
value: true
33+
- key: performance-unnecessary-value-param.AllowedTypes
34+
value: 'std::vector;.*Iterator'
35+
- key: modernize-use-nodiscard.Macros
36+
value: 'CUDA_CHECK'
37+

.github/workflows/ci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Format and Lint
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
- master
8+
9+
jobs:
10+
format-and-lint:
11+
name: Format and Lint Check
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Install pixi
19+
uses: prefix-dev/[email protected]
20+
with:
21+
pixi-version: "latest"
22+
cache: true # Cache pixi installation
23+
24+
- name: Cache pixi environment
25+
uses: actions/cache@v4
26+
with:
27+
path: |
28+
~/.pixi
29+
.pixi
30+
key: ${{ runner.os }}-pixi-${{ hashFiles('pixi.lock') }}
31+
restore-keys: |
32+
${{ runner.os }}-pixi-
33+
34+
- name: Install dependencies
35+
run: pixi install
36+
37+
- name: Check formatting
38+
run: |
39+
pixi run format
40+
if [ -n "$(git status --porcelain)" ]; then
41+
echo "❌ Files were not properly formatted. Run 'pixi run format' to fix."
42+
git diff
43+
exit 1
44+
fi
45+
46+
- name: Lint code
47+
run: pixi run lint
48+

.pre-commit-config.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Pre-commit hooks configuration for GenMetaBalls
2+
# See https://pre-commit.com for more information
3+
4+
repos:
5+
# Local hooks for custom formatting and linting
6+
- repo: local
7+
hooks:
8+
# Format files (C++/CUDA + Python)
9+
- id: format
10+
name: Format files
11+
entry: pixi run format
12+
language: system
13+
pass_filenames: false
14+
always_run: true
15+
stages: [pre-commit]
16+
17+
# Lint files (C++/CUDA + Python)
18+
- id: lint
19+
name: Lint files
20+
entry: pixi run lint
21+
language: system
22+
pass_filenames: false
23+
always_run: true
24+
stages: [pre-commit]
25+
26+
# Run tests (pre-push hook)
27+
- id: test
28+
name: Run all tests
29+
entry: scripts/test-quiet.sh
30+
language: system
31+
pass_filenames: false
32+
always_run: true
33+
stages: [pre-push]
34+
verbose: true
35+

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ check_language(CUDA)
66

77
set(CMAKE_CXX_STANDARD 20)
88

9+
# Generate compile_commands.json for clang-tidy and other tools
10+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
11+
912
################
1013
# Core Library #
1114
################

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,29 @@ Let's get the ball rolling with blazing fast CUDA kernels!
44

55
## Installation
66

7-
For initial installation, run:
7+
### Usage Setup
8+
9+
To simply run `genmetaballs`:
810

911
```bash
1012
pixi install
1113
```
1214

15+
### Development Setup
16+
17+
For development:
18+
19+
```bash
20+
pixi install
21+
pixi run dev-setup
22+
```
23+
24+
The `dev-setup` task sets up [pre-commit](https://pre-commit.com/) git hooks:
25+
- **Pre-commit**: Formats and lints code before each commit
26+
- **Pre-push**: Runs all tests before pushes
27+
28+
29+
1330
## Testing
1431

1532
### C++/CUDA Tests
@@ -35,3 +52,24 @@ To run both C++/CUDA and Python tests together:
3552
```bash
3653
pixi run test
3754
```
55+
56+
## Formatting & Linting
57+
58+
All commands work on both C++/CUDA and Python files automatically.
59+
60+
Format all files:
61+
```bash
62+
pixi run format
63+
```
64+
65+
Lint all files:
66+
```bash
67+
pixi run lint
68+
```
69+
70+
Auto-fix linting issues and format files:
71+
```bash
72+
pixi run fix
73+
```
74+
75+
These commands are automatically run by the pre-commit hooks when you commit code.

genmetaballs/src/cuda/bindings.cu

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include <cstdint>
2-
32
#include <nanobind/nanobind.h>
43
#include <nanobind/stl/vector.h>
54

@@ -11,10 +10,6 @@ constexpr uint32_t BLOCK_DIM = 1024;
1110
namespace nb = nanobind;
1211

1312
NB_MODULE(_genmetaballs_bindings, m) {
14-
m.def(
15-
"gpu_add",
16-
&gpu_add<GRID_DIM, BLOCK_DIM>,
17-
"Add two lists elementwise on the GPU",
18-
nb::arg("a"), nb::arg("b")
19-
);
13+
m.def("gpu_add", &gpu_add<GRID_DIM, BLOCK_DIM>, "Add two lists elementwise on the GPU",
14+
nb::arg("a"), nb::arg("b"));
2015
}

genmetaballs/src/cuda/core/add.cuh

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,14 @@
44

55
#include "utils.h"
66

7-
__global__ void add_kernel(
8-
float const *a,
9-
float const *b,
10-
const uint32_t n,
11-
float *sum
12-
) {
7+
__global__ void add_kernel(float const* a, float const* b, const uint32_t n, float* sum) {
138
const uint32_t i = threadIdx.x + blockIdx.x * blockDim.x;
14-
if(i < n)
9+
if (i < n)
1510
sum[i] = a[i] + b[i];
1611
}
1712

18-
template<uint32_t grid_dim, uint32_t block_dim>
19-
std::vector<float> gpu_add(
20-
const std::vector<float> &a_vec,
21-
const std::vector<float> &b_vec
22-
) {
13+
template <uint32_t grid_dim, uint32_t block_dim>
14+
std::vector<float> gpu_add(const std::vector<float>& a_vec, const std::vector<float>& b_vec) {
2315
const uint32_t n = a_vec.size();
2416
const uint32_t nbytes = n * sizeof(float);
2517
float *a, *b, *sum;

genmetaballs/src/cuda/core/utils.cu

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
#include "utils.h"
66

7-
void cuda_check(cudaError_t code, const char *file, int line) {
7+
void cuda_check(cudaError_t code, const char* file, int line) {
88
if (code != cudaSuccess) {
9-
std::cerr << "CUDA error at " << file << ":" << line << ": "
10-
<< cudaGetErrorString(code) << std::endl;
9+
std::cerr << "CUDA error at " << file << ":" << line << ": " << cudaGetErrorString(code)
10+
<< std::endl;
1111
exit(1);
1212
}
1313
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from . import _genmetaballs_bindings as _gmbb
22

3+
34
def gpu_add(a: list[float], b: list[float]) -> list[float]:
45
return _gmbb.gpu_add(a, b)

0 commit comments

Comments
 (0)