Skip to content
This repository was archived by the owner on Jan 15, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
c46ed84
added initial opsa kernel.
rubber-duck-debug Dec 12, 2023
5c74f1a
comment
rubber-duck-debug Dec 12, 2023
21d436c
loop reordering.
rubber-duck-debug Dec 12, 2023
c4caa66
spelling.
rubber-duck-debug Dec 12, 2023
7371fa9
index mistakes.
rubber-duck-debug Dec 12, 2023
d597e94
abstracted common factors
rubber-duck-debug Dec 12, 2023
4bbf948
removed uint
rubber-duck-debug Dec 12, 2023
4a2f68c
OPSA evaluation
rubber-duck-debug Feb 15, 2024
d9eaf5c
renaming
rubber-duck-debug Feb 15, 2024
61d3210
added first_occurences kernel in cuda_utils.
rubber-duck-debug Feb 16, 2024
5843fd8
formatting.
rubber-duck-debug Feb 16, 2024
aecaa94
added cudaMalloc.
rubber-duck-debug Feb 16, 2024
0183d6d
formatting.
rubber-duck-debug Feb 16, 2024
90202d4
docs.
rubber-duck-debug Feb 16, 2024
e3467bf
opsa_jvp skeleton.
rubber-duck-debug Feb 19, 2024
c59e0bd
templates and C exports.
rubber-duck-debug Feb 19, 2024
059b370
impl
rubber-duck-debug Feb 19, 2024
55a5711
added opsa vjp impl
rubber-duck-debug Feb 21, 2024
b30cd8d
vjp impl update
rubber-duck-debug Feb 21, 2024
cb9c606
starting torch integration
rubber-duck-debug Feb 21, 2024
4b4b4a7
opsa torch impl
rubber-duck-debug Feb 23, 2024
03845ef
fix to build process.
rubber-duck-debug Feb 23, 2024
e10264d
capi implementation for CUDA
rubber-duck-debug Feb 23, 2024
b365dc8
added foward declarations.
rubber-duck-debug Feb 23, 2024
55abb8a
added forward decs
rubber-duck-debug Feb 23, 2024
c5b4cf9
issue still persists...
rubber-duck-debug Feb 23, 2024
ca08740
restructuring.
rubber-duck-debug Feb 26, 2024
8aa086b
remove unecessary statement.
rubber-duck-debug Feb 26, 2024
3322674
fixed ordering in opsa
rubber-duck-debug Feb 26, 2024
f48f9bb
removed file.
rubber-duck-debug Feb 26, 2024
1b87b8b
torch integration + first occ caching
rubber-duck-debug Feb 27, 2024
bcb9e2c
fixed opsa indexing.
rubber-duck-debug Feb 27, 2024
dc39676
backwards still not correct...
rubber-duck-debug Feb 28, 2024
de92b27
fixed backwards issue.
rubber-duck-debug Feb 28, 2024
1181d81
restructuring
rubber-duck-debug Feb 29, 2024
02294e1
formatting.
rubber-duck-debug Feb 29, 2024
e34c9b0
removed unecessary header.
rubber-duck-debug Feb 29, 2024
ea6ba08
docs
rubber-duck-debug Feb 29, 2024
047875d
added forward decs.
rubber-duck-debug Feb 29, 2024
80e31fe
Format
frostedoyster Feb 29, 2024
90755eb
minor changes.
rubber-duck-debug Feb 29, 2024
0fa343c
Merge branch 'master' into cuda
rubber-duck-debug Feb 29, 2024
d2ef56a
header fixes.
rubber-duck-debug Feb 29, 2024
eaf9649
torch fixes
rubber-duck-debug Feb 29, 2024
2ad19a9
unecessary define.
rubber-duck-debug Feb 29, 2024
c8dcd6c
fixing CPU build with CUDA disabled.
rubber-duck-debug Feb 29, 2024
0614b21
added cuda check
rubber-duck-debug Feb 29, 2024
27d50c4
added conditional computation of grads.
rubber-duck-debug Feb 29, 2024
7c7f678
added size checks
rubber-duck-debug Feb 29, 2024
7e460af
linting fixes
rubber-duck-debug Feb 29, 2024
e560e41
comments
rubber-duck-debug Feb 29, 2024
bdb30c2
whitespace
rubber-duck-debug Feb 29, 2024
732364a
format
rubber-duck-debug Feb 29, 2024
2dc6022
Add benchmark option to run on CUDA
frostedoyster Feb 29, 2024
355f7f5
Merge branch 'master' into cuda
frostedoyster Feb 29, 2024
9c6ac23
CUDA example
frostedoyster Mar 2, 2024
29b71bc
fixes to make guillaume a happy chappy
rubber-duck-debug Mar 18, 2024
2e3df39
changed comments and forward mode
rubber-duck-debug Mar 18, 2024
0d06455
simpliefied call structure for kernels with mops::Tensors
rubber-duck-debug Mar 18, 2024
c3ca9e5
formatting + comments
rubber-duck-debug Mar 18, 2024
f02ea80
removed first_occurences from public API
rubber-duck-debug Mar 18, 2024
5ff929e
removed edge reference
rubber-duck-debug Mar 18, 2024
0e289c2
comment
rubber-duck-debug Mar 18, 2024
cc11e19
initial implementation for HPE, forwards only.
rubber-duck-debug Mar 21, 2024
5ffe32c
torch integration
rubber-duck-debug Mar 21, 2024
99624f0
Merge branch 'main' into cuda_hpe
rubber-duck-debug Mar 27, 2024
1aef033
Merge branch 'main' into cuda_hpe
rubber-duck-debug Mar 27, 2024
f58e527
formatting.
rubber-duck-debug Mar 27, 2024
35a540c
inital HPE VJP implementation.
rubber-duck-debug Mar 27, 2024
e74b481
HPE and HPE_VJP update to include smem impl for indices
rubber-duck-debug Apr 2, 2024
ef1b6db
fixed vjp indexing issue.
rubber-duck-debug Apr 2, 2024
476d665
Merge branch 'main' into cuda_hpe
rubber-duck-debug Apr 2, 2024
a63dbb0
endif fix
rubber-duck-debug Apr 2, 2024
5039c8a
fixed hpe and vjp CuPy tests.
rubber-duck-debug Apr 2, 2024
f87588c
formatting issues.
rubber-duck-debug Apr 2, 2024
b26a917
added in CUDA availability check.
rubber-duck-debug Apr 3, 2024
6c4541f
removed unecessary lines
rubber-duck-debug Apr 3, 2024
d58086e
preliminary CUDA SAP implementation.
rubber-duck-debug Apr 3, 2024
ae24bcb
formatting.
rubber-duck-debug Apr 3, 2024
c9f90c7
working SAP code.
rubber-duck-debug Apr 8, 2024
763bd6a
added torch support for SAP.
rubber-duck-debug Apr 8, 2024
5914804
cuda copy.
rubber-duck-debug Apr 8, 2024
ec638c4
removed cuda call from gradcheck for sap until vjp is included.
rubber-duck-debug Apr 8, 2024
2387239
removed unecessary comments
rubber-duck-debug Apr 8, 2024
e0aafd3
improved SAP implementation.
rubber-duck-debug Apr 8, 2024
839fe49
vjp implementation.
rubber-duck-debug Apr 8, 2024
4ce4489
corrected smem amount
rubber-duck-debug Apr 8, 2024
6312506
fixed nondet_tol for tests
rubber-duck-debug Apr 8, 2024
939081e
sap test
rubber-duck-debug Apr 8, 2024
23202b8
sap test
rubber-duck-debug Apr 8, 2024
dade4a6
initial SASAW kernel implementation.
rubber-duck-debug Apr 9, 2024
5f60f18
Merge branch 'main' into cuda_sasaw
rubber-duck-debug Apr 9, 2024
ce80e21
typo
rubber-duck-debug Apr 9, 2024
0d6ebe9
x
rubber-duck-debug Apr 9, 2024
e1ba3d3
Merge branch 'main' into cuda_sasaw
rubber-duck-debug Apr 10, 2024
10db372
missing variable.
rubber-duck-debug Apr 15, 2024
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
2 changes: 2 additions & 0 deletions mops/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ check_language(CUDA)
if(CMAKE_CUDA_COMPILER)
enable_language(CUDA)
set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE BOOL "" FORCE)
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -lineinfo")
else()
message(STATUS "Could not find a CUDA compiler")
endif()
Expand Down Expand Up @@ -118,6 +119,7 @@ if(CMAKE_CUDA_COMPILER)
"src/opsa/opsa.cu"
"src/hpe/hpe.cu"
"src/sap/sap.cu"
"src/sasaw/sasaw.cu"
)

endif()
Expand Down
18 changes: 18 additions & 0 deletions mops/include/mops/cuda_first_occurences.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef FIRST_OCCURENCES_HPP
#define FIRST_OCCURENCES_HPP

#include "mops/tensor.hpp"
#include <cstdint>

/*
* Computes the indexes at which the sorted input array (receiver_list) change in value, with 0
* prepended. For example, if the receiver list is [0, 0, 0, 1, 1, 1, 2, 2], then the output would
* be [0, 3, 6]. nelements_input refers to the size of the input receiver_list, nelements_output
* refers, to the number of output elements. The elements of receiver_list **must** be sorted such
* that all references to each index appear contiguously and continuously.
*/
int32_t* calculate_first_occurences_cuda(
const int32_t* receiver_list, int32_t nelements_input, int32_t nelements_output
);

#endif // FIRST_OCCURENCES_HP
45 changes: 45 additions & 0 deletions mops/include/mops/cuda_utils.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef CUDA_UTILS_CUH
#define CUDA_UTILS_CUH

#include <cstdint>
#include <cstdio>
#include <cuda.h>

using namespace std;

#define CUDA_CHECK_ERROR(err) \
do { \
cudaError_t err_cuda = err; \
if (err_cuda != cudaSuccess) { \
fprintf( \
stderr, \
"CUDA error in file '%s' in line %i: %s\n", \
__FILE__, \
__LINE__, \
cudaGetErrorString(err_cuda) \
); \
exit(EXIT_FAILURE); \
} \
} while (0)

__host__ __device__ int32_t find_integer_divisor(int32_t x, int32_t bdim);

/*
* helper function to allocate correctly sized shared memory buffers. creates a pointer reference to
* a shared memory array with n_elements number of elements. On exit, ptr is shifted right by
* nelements * sizeof(T), and space is incremented by this same amount.
*
*/
template <class T>
__host__ __device__ T* shared_array(std::size_t n_elements, void*& ptr, std::size_t* space) noexcept;

/*
* helper function to allocate correctly sized shared memory buffers identically to the shared_array
* method, but in addition are aligned to a certain byte boundary given by alignment.
*/
template <class T>
__host__ __device__ T* align_array(
std::size_t n_elements, void*& ptr, const std::size_t alignment, std::size_t* space
) noexcept;

#endif // CUDA_UTILS_CUH
38 changes: 0 additions & 38 deletions mops/src/sasaw/cuda.tpp

This file was deleted.

8 changes: 3 additions & 5 deletions mops/src/sasaw/sasaw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ template void mops::sparse_accumulation_scatter_add_with_weights_vjp<double>(
Tensor<int32_t, 1> indices_output_2
);

#ifdef MOPS_CUDA_ENABLED
#include "cuda.tpp"
#else
#ifndef MOPS_CUDA_ENABLED
template <typename scalar_t>
void mops::cuda::
sparse_accumulation_scatter_add_with_weights(Tensor<scalar_t, 3>, Tensor<scalar_t, 2>, Tensor<scalar_t, 2>, Tensor<scalar_t, 1>, Tensor<scalar_t, 3>, Tensor<int32_t, 1>, Tensor<int32_t, 1>, Tensor<int32_t, 1>, Tensor<int32_t, 1>, Tensor<int32_t, 1>) {
Expand All @@ -74,8 +72,6 @@ void mops::cuda::
throw std::runtime_error("MOPS was not compiled with CUDA support");
}

#endif

// explicit instantiations of CUDA templates
template void mops::cuda::sparse_accumulation_scatter_add_with_weights<float>(
Tensor<float, 3> output,
Expand Down Expand Up @@ -134,3 +130,5 @@ template void mops::cuda::sparse_accumulation_scatter_add_with_weights_vjp<doubl
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
);

#endif
226 changes: 225 additions & 1 deletion mops/src/sasaw/sasaw.cu
Original file line number Diff line number Diff line change
@@ -1 +1,225 @@
// todo: cuda device code
#include "mops/sasaw.hpp"

#include "internal/checks.hpp"
#include "internal/cuda_first_occurences.cuh"
#include "internal/cuda_utils.cuh"

#define WARP_SIZE 32
#define NWARPS_PER_BLOCK 4

using namespace mops;
using namespace mops::cuda;

template <typename scalar_t>
__global__ __launch_bounds__(WARP_SIZE* NWARPS_PER_BLOCK) void sparse_accumulation_scatter_add_with_weights_kernel(
Tensor<scalar_t, 3> output,
Tensor<scalar_t, 2> A,
Tensor<scalar_t, 2> B,
Tensor<scalar_t, 1> C,
Tensor<scalar_t, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2,
Tensor<int32_t, 1> first_occurences
) {

extern __shared__ char buffer[];

void* sptr = buffer;
size_t space = 0;

scalar_t* buffer_out = shared_array<scalar_t>(output.shape[1] * output.shape[2], sptr, &space);
scalar_t* buffer_A = shared_array<scalar_t>(NWARPS_PER_BLOCK * A.shape[1], sptr, &space);
scalar_t* buffer_B = shared_array<scalar_t>(NWARPS_PER_BLOCK * B.shape[1], sptr, &space);
scalar_t* buffer_W =
shared_array<scalar_t>(NWARPS_PER_BLOCK * *W.shape[1] * W.shape[2], sptr, &space);

scalar_t* buffer_C = shared_array<scalar_t>(C.shape[0], sptr, &space);
int8_t* buffer_indices_A = shared_array<int8_t>(indices_A.shape[0], sptr, &space);
int8_t* buffer_indices_W_2 = shared_array<int8_t>(indices_W_2.shape[0], sptr, &space);
int8_t* buffer_indices_output_2 = shared_array<int8_t>(indices_output_2.shape[0], sptr, &space);

int laneID = threadIdx.x % WARP_SIZE;
int warpID = threadIdx.x / WARP_SIZE;

int32_t sample_start = first_occurences.data[blockIdx.x];
int32_t sample_end = -1;
int32_t node_index = -1;

if (sample_start != -1) {
node_index = indices_output_1.data[sample_start];
sample_end = (blockIdx.x == first_occurences.shape[0] - 1)
? indices_output_1.shape[0]
: (first_occurences.data[blockIdx.x + 1] == -1
? indices_output_1.shape[0]
: first_occurences.data[blockIdx.x + 1]);
}

int32_t nsamples = sample_end - sample_start;

if (nsamples == 0) {
return;
}

for (int tid = threadIdx.x; tid < indices_A.shape[0]; tid += blockDim.x) {
buffer_indices_A[tid] = (int8_t)indices_A.data[tid];
buffer_indices_W_2[tid] = (int8_t)indices_W_2.data[tid];
buffer_C[tid] = C.data[tid];
buffer_indices_output_2[tid] = (int8_t)indices_output_2.data[tid];
}

for (int tid = threadIdx.x; tid < output.shape[1] * output.shape[2]; tid += blockDim.x) {
buffer_out[tid] = 0.0;
}

__syncthreads();

for (int sample_idx = 0; sample_idx < nsamples; sample_idx++) {

int sample = sample_start + sample_idx + warpID;

if (sample >= sample_end) {
break;
}

// load in temporary buffers for each sample

for (int tid = laneID; tid < A.shape[1]; tid += WARP_SIZE) {
buffer_A[warpID * A.shape[1] + tid] = A.data[sample * A.shape[1] + tid];
}

for (int tid = laneID; tid < B.shape[1]; tid += WARP_SIZE) {
buffer_B[warpID * B.shape[1] + tid] = B.data[sample * B.shape[1] + tid];
}

for (int j = 0; j < W.shape[1]; j++) {
for (int tid = laneID; tid < W.shape[2]; tid += WARP_SIZE) {
buffer_W[warpID * W.shape[1] * W.shape[2] + j * W.shape[2] + tid] =
W.data[indices_W_1.data[sample] * W.shape[1] * W.shape[2] + j * W.shape[2] + tid];
}
}

__syncwarp();

for (int k = 0; k < C.shape[0]; k++) {
for (int tid = laneID; tid < W.shape[2]; tid += WARP_SIZE) {
scalar_t w =
buffer_W[warpID * W.shape[1] * W.shape[2] + buffer_indices_W_2[k] * W.shape[2] + tid];

int32_t a_idx = buffer_indices_A[k];
int32_t index_output_2 = buffer_indices_output_2[k];

atomicAdd(
&buffer_out[index_output_2 * output.shape[2] + tid],
A.data[sample * A.shape[1] + a_idx] * B[sample * B.shape[1] + tid] *
buffer_C[k] * w
);
}
}
}

__syncthreads();

for (int i = warpID; i < output.shape[1]; i += NWARPS_PER_BLOCK) {
for (int j = laneID; j < output.shape[2]; j += WARP_SIZE) {
output.data[node_index * output.shape[1] * output.shape[2] + i * output.shape[2] + j] =
buffer_out[i * output.shape[2] + j];
}
}
}

template <typename scalar_t>
void mops::cuda::sparse_accumulation_scatter_add_with_weights(
Tensor<scalar_t, 3> output,
Tensor<scalar_t, 2> A,
Tensor<scalar_t, 2> B,
Tensor<scalar_t, 1> C,
Tensor<scalar_t, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
) {
// TODO
}

// explicit instantiations of CUDA templates
template void mops::cuda::sparse_accumulation_scatter_add_with_weights<float>(
Tensor<float, 3> output,
Tensor<float, 2> A,
Tensor<float, 2> B,
Tensor<float, 1> C,
Tensor<float, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
);

template void mops::cuda::sparse_accumulation_scatter_add_with_weights<double>(
Tensor<double, 3> output,
Tensor<double, 2> A,
Tensor<double, 2> B,
Tensor<double, 1> C,
Tensor<double, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
);

template <typename scalar_t>
void mops::cuda::sparse_accumulation_scatter_add_with_weights_vjp(
Tensor<scalar_t, 2> grad_A,
Tensor<scalar_t, 2> grad_B,
Tensor<scalar_t, 3> grad_W,
Tensor<scalar_t, 3> grad_output,
Tensor<scalar_t, 2> A,
Tensor<scalar_t, 2> B,
Tensor<scalar_t, 1> C,
Tensor<scalar_t, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
) {
// TODO
}

template void mops::cuda::sparse_accumulation_scatter_add_with_weights_vjp<float>(
Tensor<float, 2> grad_A,
Tensor<float, 2> grad_B,
Tensor<float, 3> grad_W,
Tensor<float, 3> grad_output,
Tensor<float, 2> A,
Tensor<float, 2> B,
Tensor<float, 1> C,
Tensor<float, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
);

template void mops::cuda::sparse_accumulation_scatter_add_with_weights_vjp<double>(
Tensor<double, 2> grad_A,
Tensor<double, 2> grad_B,
Tensor<double, 3> grad_W,
Tensor<double, 3> grad_output,
Tensor<double, 2> A,
Tensor<double, 2> B,
Tensor<double, 1> C,
Tensor<double, 3> W,
Tensor<int32_t, 1> indices_A,
Tensor<int32_t, 1> indices_W_1,
Tensor<int32_t, 1> indices_W_2,
Tensor<int32_t, 1> indices_output_1,
Tensor<int32_t, 1> indices_output_2
);
Loading