Skip to content
Merged
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
119 changes: 119 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
---
Language: Cpp
Standard: c++20
BasedOnStyle: LLVM
IndentWidth: 4
TabWidth: 4
UseTab: Never
ColumnLimit: 100
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<.*\.(cu|cu\.h|cuh|hpp|h)$'
Priority: 1
- Regex: '^<.*\.(cpp|cc|c\+\+|cxx|c)$'
Priority: 2
- Regex: '^<.*'
Priority: 3
- Regex: '.*'
Priority: 4
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
...

37 changes: 37 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
# Clang-tidy configuration for CUDA/C++ project
Checks: >
-*,
bugprone-*,
cert-*,
cppcoreguidelines-*,
performance-*,
readability-*,
modernize-*,
-bugprone-easily-swappable-parameters,
-readability-identifier-length,
-readability-identifier-naming,
-readability-named-parameter,
-readability-implicit-bool-conversion,
-cppcoreguidelines-avoid-magic-numbers,
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
-cppcoreguidelines-pro-type-union-access,
-cppcoreguidelines-pro-type-vararg,
-cppcoreguidelines-owning-memory,
-modernize-use-trailing-return-type,
-readability-magic-numbers

WarningsAsErrors: ''
HeaderFilterRegex: '.*'
FormatStyle: 'file'
CheckOptions:
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: true
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
value: true
- key: performance-unnecessary-value-param.AllowedTypes
value: 'std::vector;.*Iterator'
- key: modernize-use-nodiscard.Macros
value: 'CUDA_CHECK'

48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Format and Lint

on:
pull_request:
branches:
- main
- master

jobs:
format-and-lint:
name: Format and Lint Check
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install pixi
uses: prefix-dev/[email protected]
with:
pixi-version: "latest"
cache: true # Cache pixi installation

- name: Cache pixi environment
uses: actions/cache@v4
with:
path: |
~/.pixi
.pixi
key: ${{ runner.os }}-pixi-${{ hashFiles('pixi.lock') }}
restore-keys: |
${{ runner.os }}-pixi-

- name: Install dependencies
run: pixi install
Comment on lines +34 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Install pixi" step (line 18) is already implicitly running pixi install --locked under the hood, so we probably don't need to explicitly run pixi install again. Let's get rid of this in the future :)


- name: Check formatting
run: |
pixi run format
if [ -n "$(git status --porcelain)" ]; then
echo "❌ Files were not properly formatted. Run 'pixi run format' to fix."
git diff
exit 1
fi

- name: Lint code
run: pixi run lint

35 changes: 35 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Pre-commit hooks configuration for GenMetaBalls
# See https://pre-commit.com for more information

repos:
# Local hooks for custom formatting and linting
- repo: local
hooks:
# Format files (C++/CUDA + Python)
- id: format
name: Format files
entry: pixi run format
language: system
pass_filenames: false
always_run: true
stages: [pre-commit]

# Lint files (C++/CUDA + Python)
- id: lint
name: Lint files
entry: pixi run lint
language: system
pass_filenames: false
always_run: true
stages: [pre-commit]

# Run tests (pre-push hook)
- id: test
name: Run all tests
entry: scripts/test-quiet.sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this not using the pixi run test task that we already have?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does do that! (running ctest and pytest), but suppress the output to be quiet. I think everytime we push, it might get messy to have a a barrage of stdout or stderr. But honestly, who cares, we can remove this too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. TBH I prefer a pixi run test to a whole separate file in the codebase, but I do understand it's a matter of taste. I'm fine with keeping it this way.

language: system
pass_filenames: false
always_run: true
stages: [pre-push]
verbose: true

3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ check_language(CUDA)

set(CMAKE_CXX_STANDARD 20)

# Generate compile_commands.json for clang-tidy and other tools
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

################
# Core Library #
################
Expand Down
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,29 @@ Let's get the ball rolling with blazing fast CUDA kernels!

## Installation

For initial installation, run:
### Usage Setup

To simply run `genmetaballs`:

```bash
pixi install
```

### Development Setup

For development:

```bash
pixi install
pixi run dev-setup
```

The `dev-setup` task sets up [pre-commit](https://pre-commit.com/) git hooks:
- **Pre-commit**: Formats and lints code before each commit
- **Pre-push**: Runs all tests before pushes



## Testing

### C++/CUDA Tests
Expand All @@ -35,3 +52,24 @@ To run both C++/CUDA and Python tests together:
```bash
pixi run test
```

## Formatting & Linting

All commands work on both C++/CUDA and Python files automatically.

Format all files:
```bash
pixi run format
```

Lint all files:
```bash
pixi run lint
```

Auto-fix linting issues and format files:
```bash
pixi run fix
```

These commands are automatically run by the pre-commit hooks when you commit code.
9 changes: 2 additions & 7 deletions genmetaballs/src/cuda/bindings.cu
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include <cstdint>

#include <nanobind/nanobind.h>
#include <nanobind/stl/vector.h>

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

NB_MODULE(_genmetaballs_bindings, m) {
m.def(
"gpu_add",
&gpu_add<GRID_DIM, BLOCK_DIM>,
"Add two lists elementwise on the GPU",
nb::arg("a"), nb::arg("b")
);
m.def("gpu_add", &gpu_add<GRID_DIM, BLOCK_DIM>, "Add two lists elementwise on the GPU",
nb::arg("a"), nb::arg("b"));
}
16 changes: 4 additions & 12 deletions genmetaballs/src/cuda/core/add.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,14 @@

#include "utils.h"

__global__ void add_kernel(
float const *a,
float const *b,
const uint32_t n,
float *sum
) {
__global__ void add_kernel(float const* a, float const* b, const uint32_t n, float* sum) {
const uint32_t i = threadIdx.x + blockIdx.x * blockDim.x;
if(i < n)
if (i < n)
sum[i] = a[i] + b[i];
}

template<uint32_t grid_dim, uint32_t block_dim>
std::vector<float> gpu_add(
const std::vector<float> &a_vec,
const std::vector<float> &b_vec
) {
template <uint32_t grid_dim, uint32_t block_dim>
std::vector<float> gpu_add(const std::vector<float>& a_vec, const std::vector<float>& b_vec) {
const uint32_t n = a_vec.size();
const uint32_t nbytes = n * sizeof(float);
float *a, *b, *sum;
Expand Down
6 changes: 3 additions & 3 deletions genmetaballs/src/cuda/core/utils.cu
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

#include "utils.h"

void cuda_check(cudaError_t code, const char *file, int line) {
void cuda_check(cudaError_t code, const char* file, int line) {
if (code != cudaSuccess) {
std::cerr << "CUDA error at " << file << ":" << line << ": "
<< cudaGetErrorString(code) << std::endl;
std::cerr << "CUDA error at " << file << ":" << line << ": " << cudaGetErrorString(code)
<< std::endl;
exit(1);
}
}
1 change: 1 addition & 0 deletions genmetaballs/src/genmetaballs/gpu_add.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from . import _genmetaballs_bindings as _gmbb


def gpu_add(a: list[float], b: list[float]) -> list[float]:
return _gmbb.gpu_add(a, b)
Loading
Loading