Open3D (C++ API)  0.20.0
Loading...
Searching...
No Matches
SparseConvSYCL.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2026 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7
8// SYCL port of SparseConv.cuh. Structurally identical to the CUDA version:
9// same two-pass temp-size query (see MemoryAllocation.h, reused verbatim -
10// it is pure host-side bookkeeping, no CUDA/SYCL dependency), same
11// chunked-GEMM loop over `num_cols_per_run` output points at a time. Only
12// device-specific pieces changed: cudaStream_t -> sycl::queue&,
13// cudaMemsetAsync -> queue.fill, CUTLASS 2.x device::Gemm -> the sycl-tla
14// backed GemmColumnMajorSYCL shim (see GemmSYCL.h). Each chunk's FillColumn
15// depends on the previous chunk's GEMM completion event (both write
16// into/read from the shared `columns` scratch buffer); GemmColumnMajorSYCL
17// does not block, so this event dependency is what keeps chunks correctly
18// ordered.
19#pragma once
20
25
27
28namespace open3d {
29namespace ml {
30namespace impl {
31
34template <class TFeat, class TOut, class TIndex, class TKernelIndex>
36 void* temp,
37 size_t& temp_size,
38 size_t& max_temp_size,
39 int texture_alignment,
40 TOut* out_features,
41 const std::vector<int>& filter_dims,
42 const TFeat* filter,
43 TIndex num_out,
44 TIndex num_inp,
45 const TFeat* inp_features,
46 const TFeat* inp_importance,
47 size_t neighbors_index_size,
48 const TIndex* neighbors_index,
49 const TKernelIndex* neighbors_kernel_index,
50 const TFeat* neighbors_importance,
51 const int64_t* neighbors_row_splits,
52 bool normalize,
53 bool allow_tf32) {
54 const bool get_temp_size = !temp;
55
56 if (get_temp_size) {
57 temp = (char*)1; // worst case alignment
58 temp_size = std::numeric_limits<int64_t>::max();
59 }
60
61 MemoryAllocation mem_temp(temp, temp_size, texture_alignment);
62
63 const int in_channels = filter_dims[filter_dims.size() - 2];
64 const int out_channels = filter_dims[filter_dims.size() - 1];
65
66 int num_kernel_elements = 1;
67 for (size_t i = 0; i < filter_dims.size() - 2; ++i)
68 num_kernel_elements *= filter_dims[i];
69
70 // We want to allocate memory for at least 32 output points.
71 const size_t min_num_cols_per_run = std::min(size_t(num_out), size_t(32));
72 const size_t max_num_cols_per_run = num_out;
73 const size_t bytes_per_column =
74 sizeof(TFeat) * (num_kernel_elements * in_channels);
75 const size_t min_temp_size_bytes = min_num_cols_per_run * bytes_per_column;
76 const size_t max_temp_size_bytes = max_num_cols_per_run * bytes_per_column;
77
78 if (get_temp_size) {
79 std::pair<char*, size_t> tmp =
80 mem_temp.Alloc<char>(min_temp_size_bytes);
81 temp_size = mem_temp.MaxUsed();
82 mem_temp.Free(tmp);
83 mem_temp.Alloc<char>(max_temp_size_bytes);
84 max_temp_size = mem_temp.MaxUsed();
85 return;
86 }
87
88 std::pair<void*, size_t> mem_columns = mem_temp.AllocLargestSegment();
89
90 if (mem_columns.second < min_temp_size_bytes) {
91 std::stringstream ss;
92 ss << "temp is too small " << mem_columns.second
93 << " bytes. Expected at least " << min_temp_size_bytes << " bytes\n";
94 throw std::runtime_error(ss.str());
95 }
96
97 sycl::event out_features_fill_event =
98 queue.fill(out_features, TOut(0), size_t(num_out) * out_channels);
99
100 size_t num_cols_per_run =
101 std::min(mem_columns.second / bytes_per_column, size_t(num_out));
102
103 TFeat* columns = (TFeat*)mem_columns.first;
104
105 size_t num_runs = DivUp(num_out, num_cols_per_run);
106 // Each chunk's GEMM reads the `columns` buffer that chunk's FillColumn
107 // just wrote, so it depends on that specific FillColumn event (via
108 // GemmColumnMajorSYCL's ext_oneapi_submit_barrier, see GemmSYCL.h)
109 // rather than assuming queue order. GemmColumnMajorSYCL does NOT block
110 // before returning (see GemmSYCL.h), so the NEXT chunk's FillColumn --
111 // which reuses the same `columns` scratch buffer -- must explicitly
112 // depend on the previous chunk's GEMM event.
113 sycl::event prev_gemm_event;
114 for (size_t run_i = 0; run_i < num_runs; ++run_i) {
115 const TIndex begin_idx = TIndex(run_i * num_cols_per_run);
116 const TIndex end_idx = TIndex(
117 std::min(size_t(num_out), (run_i + 1) * num_cols_per_run));
118 const size_t num_cols_this_run = end_idx - begin_idx;
119
120 sycl::event fill_column_event = FillColumnSYCL<TFeat, TIndex,
121 TKernelIndex>(
122 queue, columns, in_channels, begin_idx, end_idx, num_out,
123 num_inp, inp_features, inp_importance, neighbors_index_size,
124 neighbors_index, neighbors_kernel_index, neighbors_importance,
125 neighbors_row_splits, num_kernel_elements, normalize,
126 run_i == 0 ? std::vector<sycl::event>{out_features_fill_event}
127 : std::vector<sycl::event>{prev_gemm_event});
128
129 // C(MxN) = A(MxK) * B(KxN); A=filter, B=columns, C=out_features.
130 const int m = out_channels;
131 const int k = num_kernel_elements * in_channels;
132 const int n = static_cast<int>(num_cols_this_run);
133 const float alpha = 1;
134 const float* const A = filter;
135 const int lda = m;
136 const float* const B = columns;
137 const int ldb = k;
138 const float beta = 1;
139 float* C = out_features + run_i * num_cols_per_run * out_channels;
140 const int ldc = m;
141
142 prev_gemm_event = GemmColumnMajorSYCL<cutlass::layout::ColumnMajor,
143 cutlass::layout::ColumnMajor>(
144 queue, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc, allow_tf32,
145 {fill_column_event});
146 }
147}
148
149} // namespace impl
150} // namespace ml
151} // namespace open3d
Eigen::Matrix3d B
Definition PointCloudPlanarPatchDetection.cpp:523
sycl::queue queue
Definition SYCLContext.cpp:88
A class for managing memory segments within a memory allocation.
Definition MemoryAllocation.h:21
void Free(const std::pair< T *, size_t > &segment)
Frees a previously returned segment.
Definition MemoryAllocation.h:85
std::pair< void *, size_t > AllocLargestSegment()
Returns the largest free segment.
Definition MemoryAllocation.h:75
size_t MaxUsed() const
Returns the peak memory usage in bytes.
Definition MemoryAllocation.h:145
std::pair< T *, size_t > Alloc(size_t size)
Definition MemoryAllocation.h:48
sycl::event FillColumnSYCL(sycl::queue &queue, TFeat *columns, int in_channels, TIndex begin_idx, TIndex end_idx, TIndex num_out, const TReal *const out_positions, TIndex num_inp, const TReal *const inp_positions, const TFeat *const inp_features, const TFeat *const inp_importance, size_t neighbors_index_size, const TIndex *const neighbors_index, const TFeat *const neighbors_importance, const int64_t *const neighbors_row_splits, const TReal *const extents, const TReal *const offsets, const std::vector< int > &filter_dims, InterpolationMode interpolation, CoordinateMapping coordinate_mapping, bool align_corners, bool individual_extent, bool isotropic_extent, bool normalize, const std::vector< sycl::event > &deps)
Definition ContinuousConvSYCLKernels.cpp:462
void SparseConvComputeFeaturesSYCL(sycl::queue &queue, void *temp, size_t &temp_size, size_t &max_temp_size, int texture_alignment, TOut *out_features, const std::vector< int > &filter_dims, const TFeat *filter, TIndex num_out, TIndex num_inp, const TFeat *inp_features, const TFeat *inp_importance, size_t neighbors_index_size, const TIndex *neighbors_index, const TKernelIndex *neighbors_kernel_index, const TFeat *neighbors_importance, const int64_t *neighbors_row_splits, bool normalize, bool allow_tf32)
Definition SparseConvSYCL.h:35
sycl::event GemmColumnMajorSYCL(sycl::queue &queue, int m, int n, int k, float alpha, const float *A, int64_t lda, const float *B, int64_t ldb, float beta, float *C, int64_t ldc, bool allow_tf32, const std::vector< sycl::event > &deps)
Definition GemmSYCL.cpp:462
int DivUp(int x, int y)
Computes the quotient of x/y with rounding up.
Definition Helper.h:176
Definition PinholeCameraIntrinsic.cpp:16