|
Open3D (C++ API)
0.19.0
|
Host driver for SYCL nearest-neighbor search (KNN, fixed-radius, hybrid). More...
#include <algorithm>#include <functional>#include <limits>#include <numeric>#include <oneapi/dpl/algorithm>#include <oneapi/dpl/execution>#include <oneapi/dpl/numeric>#include <sycl/sycl.hpp>#include "open3d/core/SYCLUtils.h"#include "open3d/core/Tensor.h"#include "open3d/core/linalg/AddMM.h"#include "open3d/core/nns/FixedRadiusIndex.h"#include "open3d/core/nns/KnnIndex.h"#include "open3d/core/nns/NeighborSearchAllocator.h"#include "open3d/core/nns/kernel/FixedRadiusSearchSYCLImpl.h"#include "open3d/core/nns/kernel/KnnSearchSYCLImpl.h"#include "open3d/utility/Logging.h"Namespaces | |
| namespace | open3d |
| namespace | open3d::core |
| namespace | open3d::core::nns |
Macros | |
| #define | INSTANTIATE(T, TIndex) |
Functions | |
| template<class T , class TIndex > | |
| void | open3d::core::nns::KnnSearchSYCL (const Tensor &points, const Tensor &points_row_splits, const Tensor &queries, const Tensor &queries_row_splits, int knn, Tensor &neighbors_index, Tensor &neighbors_row_splits, Tensor &neighbors_distance, int64_t tile_bytes, int64_t max_tile_queries, int64_t tile_points_alignment, bool force_addmm_path) |
| template<class T , class TIndex > | |
| void | open3d::core::nns::FixedRadiusSearchSYCL (const Tensor &points, const Tensor &queries, double radius, const Tensor &points_row_splits, const Tensor &queries_row_splits, const Tensor &hash_table_splits, const Tensor &hash_table_index, const Tensor &hash_table_cell_splits, const Metric metric, const bool ignore_query_point, const bool return_distances, const bool sort, Tensor &neighbors_index, Tensor &neighbors_row_splits, Tensor &neighbors_distance, int64_t) |
| template<class T , class TIndex > | |
| void | open3d::core::nns::HybridSearchSYCL (const Tensor &points, const Tensor &queries, double radius, int max_knn, const Tensor &points_row_splits, const Tensor &queries_row_splits, const Tensor &hash_table_splits, const Tensor &hash_table_index, const Tensor &hash_table_cell_splits, const Metric metric, Tensor &neighbors_index, Tensor &neighbors_count, Tensor &neighbors_distance, int64_t) |
| template void | open3d::core::nns::BuildSpatialHashTableSYCL< float > (const Tensor &points, double radius, const Tensor &points_row_splits, const Tensor &hash_table_splits, Tensor &hash_table_index, Tensor &hash_table_cell_splits) |
| template void | open3d::core::nns::BuildSpatialHashTableSYCL< double > (const Tensor &points, double radius, const Tensor &points_row_splits, const Tensor &hash_table_splits, Tensor &hash_table_index, Tensor &hash_table_cell_splits) |
Host driver for SYCL nearest-neighbor search (KNN, fixed-radius, hybrid).
What lives here
radius (grid).max_knn within radius + counts (grid).Callers: NearestNeighborSearch / KnnIndex / FixedRadiusIndex when dataset and query tensors are on a SYCL device. CPU tensors use NanoFlann.
Includes: KNN device code in kernel/KnnSearchSYCLImpl.h; uniform-grid kernels in kernel/FixedRadiusSearchSYCLImpl.h. Short index: nns/SYCL_DESIGN.md. This file header is the maintainer reference for path selection and end-to-end flow.
| Function | Purpose |
|---|---|
| KnnSearchSYCL | Fixed k nearest neighbors (L2), batched queries × |
dataset | | FixedRadiusSearchSYCL | All neighbors within radius (variable output size per query) | | HybridSearchSYCL | Up to max_knn closest neighbors within radius + in-radius count |
Fixed-radius and hybrid share the same spatial-hash grid index built in FixedRadiusIndex::SetTensorData (see FixedRadiusSearchSYCLImpl.h). The sections below focus on KNN; grid search is summarized at the end.
For each batch, batch_knn = min(knn, num_points) (convention C5). CUDA KNN uses two strategies (small brute + GEMM + FAISS warp/block select); SYCL uses three paths:
Decision tree
force_addmm_path == false and 1 ≤ dim ≤ 8 and batch_knn ≤ 32 → Direct brute-force L2 (UseKnnDirect / DispatchKnnDirect).batch_knn ≤ 512 → AddMM fused (running heap per query tile).partial_sort).force_addmm_path=true is for benchmarks only — always skips Direct.
| Path | When | CUDA analogue | SYCL implementation | |---—|---—|------------—|------------------—| | Direct | !force_addmm ∧ dim∈[1,8] ∧ k≤32 | Small dim/k brute kernel | Sub-group SLM tiles + shuffle-merge top-k | | AddMM fused | else, k≤512 | GEMM + FAISS BlockSelect / heap | oneMKL AddMM + fused UpdateTopKFromTile | | AddMM large-k | else, k>512 | Multi-pass FAISS select | Tile select/merge + serial partial_sort (P8) |
Constants: kSYCLKnnSmallKMax = 32, kSYCLKnnMidKMax = 512 (see KnnSearchSYCLImpl.h).
Idea: Compute L2 as Σ_d (p_d − q_d)² directly — no AddMM, no data centering, no deferred ‖q‖² term.
Algorithm
NDIM (1…8) and K bucket (1…32). Float typically uses sub-group size 16; double prefers 8 when supported.Typical use: 3D point clouds, small k — often the fastest path on Intel Xe.
Idea: Expand squared L2 as ‖q‖² − 2 q·p + ‖p‖². oneMKL AddMM builds the −2 q·p tile for each (query-tile × point-tile) pair; top-k selection fuses ‖p‖² and running heap updates (UpdateTopKFromTile, FinalizeTopK).
Algorithm
KBucket(batch_knn)).FinalizeTopK: heap-sort, add ‖q‖², write batch_knn neighbors.Heap storage: k ≤ 32 → GRF-resident; k ∈ {64…512} → per-work-item scratch.
Idea: Same tiled AddMM and centering as fused path, but SelectTopKQueries
Algorithm
AddQueryNormsToDistances (add ‖q‖², clamp).P8 caveat: For very large k, merge/select may fall back to per-query serial partial_sort (oneDPL has no cheap segmented top-k) — correct but slow.
| Topic | CUDA | SYCL (this file) |
|---|---|---|
| Small k, low dim | Brute + GEMM paths | + Direct sub-group path (no |
GEMM) | | GEMM | cuBLAS | oneMKL via AddMM | | Top-k on GEMM tiles | FAISS warp/block select | Custom heap / select-merge / oneDPL | | Float32 stability | Uses norms as-is on GEMM path | Centers data before AddMM | | Large k | Multi-pass masking (1024/2048) | Select/merge + partial_sort per query |
| Id | Rule |
|---|---|
| P2 | Tile stores partial distance −2qp + ‖p‖²; ‖q‖² added once in |
finalize | | C1 | Clamp partial / final distance ≥ 0 | | C4 | Equal distance → smaller point index wins | | C5 | batch_knn = min(knn,
num_points) (caller / driver) |
Idea: Return every dataset point within radius of each query; output length varies per query (CSR layout). Ported from CUDA FixedRadiusSearchImpl.cuh; device detail in FixedRadiusSearchSYCLImpl.h.
Grid build (once per index, FixedRadiusIndex::SetTensorData):
2×radius.BuildSpatialHashTableSYCL: count points per cell → oneDPL inclusive scan → scatter into CSR (hash_table_cell_splits, hash_table_index).Query algorithm
CountNeighborsSYCL — for each query, visit 8 corner-adjacent bins; count points with squared L2 ≤ radius².neighbors_row_splits; allocate index (and optional distance) buffers for the total neighbor count.WriteNeighborsSYCL — same 8 bins; write indices and squared distances.sort=true:** SortNeighborsByDistanceSYCL — segmented oneDPL sort_by_key per query (ties not secondarily ordered by index; matches CUDA cub::DeviceSegmentedRadixSort::SortPairs).Typical use: full neighborhood inside a ball, not a fixed-k cap.
Idea: Count all in-radius neighbors, but store only the closest max_knn in fixed (num_queries, max_knn) tensors plus per-query in-radius counts. Same grid as fixed-radius (BuildSpatialHashTableSYCL).
Algorithm
WriteNeighborsHybridSYCL: one pass over 8 bins per query — running top-max_knn (replace-current-max), full in-radius count, then bounded bubble sort (≤ max_knn) for ascending distance order.Typical use: FPFH, normals, covariances — “up to K neighbors inside radius.”
Note: Could be expressed as KNN-then-filter; deferred because the grid port already avoids O(queries × points) brute force.
| Role | CUDA | SYCL |
|---|---|---|
| Dense GEMM | cuBLAS | oneMKL |
| Prefix sum | CUB | oneDPL / work-group scan |
| Segmented sort | CUB radix | oneDPL sort_by_key |
| Parallel loops | CUDA kernels | SYCL queues / ParallelFor |
force_addmm_path forces GEMM paths for regression / benchmark parity testing.| File | Role |
|---|---|
KnnSearchSYCLImpl.h | Direct / AddMM SYCL kernels, KBucket, thresholds |
| | FixedRadiusSearchSYCLImpl.h | Grid build, count/write/sort/hybrid kernels | | NearestNeighborSearch.cpp | Device dispatch to this driver | | AddMM.h | oneMKL batched GEMM for KNN tiles |
| #define INSTANTIATE | ( | T, | |
| TIndex | |||
| ) |