Vamana build optimization set and fp16 support - #2264
Conversation
(cherry picked from commit 14e36b3)
(cherry picked from commit d8b547b)
(cherry picked from commit 4d970e0)
…L2 comparators. (cherry picked from commit 0746d15)
…e vector in shared memory in the RobustPrune occlusion loop (cherry picked from commit f45fd1b49283434eb4a3017da069ead501e938c3)
…efix sum with cub scan and hoist per-batch reverse-edge allocations (cherry picked from commit 3b8650f5ebea52421f187332a2f6f3bdd599c42e)
…lusion across multiple warps per query (raise occupancy) (cherry picked from commit 2e02f938f97e65ca073daf07397d538432b52867)
… query->existing-edge distances in the RobustPrune merge (avoid recompute) (cherry picked from commit 041d355c585b7f98302d054b80ac287d637a07e4)
…oords in FP16 smem for dim>=512 to raise GreedySearch occupancy (salvage of N8)
…nce (one warp) instead of redundantly on all 128 threads, then broadcast
…ck (4 vs 8) to raise occupancy/MLP on the degree-64 occlusion sweep
| #define KERNEL_TIMING (RAFT_LOG_ACTIVE_LEVEL <= RAPIDS_LOGGER_LOG_LEVEL_DEBUG) | ||
|
|
||
| template <typename accT, typename IdxT> | ||
| __global__ void gather_query_sizes(QueryCandidates<IdxT, accT>* query_list, |
There was a problem hiding this comment.
Do you have a sense for how much this is adding to the binary size? @divyegala should be able to explain how to see the deployed metrics for PRs.
|
/ok to test c055c60 |
tarang-jain
left a comment
There was a problem hiding this comment.
I have not looked into the implementation itself (what the code inside the kernels does) and my review continues to be along the same direction as my previous comments -- to improve overall code quality and readability. Pointing out a couple of very small things.
|
|
||
| const int laneId = threadIdx.x & 31; | ||
| const int warpId = threadIdx.x >> 5; | ||
| const int num_warps = blockDim.x >> 5; |
There was a problem hiding this comment.
Lets keep this simple. I have been advised by @tfeher in the past to not use bit arithmetic for simple division / mod operations, since the compiler is typically smart enough to automatically simplify these. So we can do again things like laneId = threadIdx.x % raft::WarpSize and warpId = threadIdx.x / 32.
There was a problem hiding this comment.
I think this can also be ignored @bkarsin . Its too much nit-picking.
| auto scan_temp_storage = raft::make_device_mdarray<uint8_t>( | ||
| res, large_ws, raft::make_extents<int64_t>(std::max(scan_temp_bytes, size_t{1}))); | ||
|
|
||
| thrust::device_vector<IdxT> edge_dest_vec(max_total_edges); |
There was a problem hiding this comment.
Use raft::device_vector here
|
/ok to test e1e0b7e |
|
/ok to test f0579f9 |
| __device__ SUMTYPE l2_ILP2_half(Point<__half, SUMTYPE>* src_vec, Point<__half, SUMTYPE>* dst_vec) | ||
| { | ||
| __half temp_dst[2] = {__float2half(0.0f), __float2half(0.0f)}; | ||
| __half partial_sum[2] = {__float2half(0.0f), __float2half(0.0f)}; | ||
| for (int i = threadIdx.x; i < src_vec->Dim; i += 2 * blockDim.x) { | ||
| temp_dst[0] = dst_vec->coords[i]; | ||
| if (i + raft::WarpSize < src_vec->Dim) temp_dst[1] = dst_vec->coords[i + raft::WarpSize]; | ||
|
|
||
| l2_half_fma_sq(partial_sum[0], src_vec[0].coords[i], temp_dst[0]); | ||
| if (i + raft::WarpSize < src_vec->Dim) | ||
| l2_half_fma_sq(partial_sum[1], src_vec[0].coords[i + raft::WarpSize], temp_dst[1]); | ||
| } | ||
| partial_sum[0] = __hadd(partial_sum[0], partial_sum[1]); | ||
|
|
||
| return l2_half_warp_reduce<SUMTYPE>(partial_sum[0]); | ||
| } |
There was a problem hiding this comment.
Would it make sense to also provide an overload of l2_half_fma_sq with half2 type? I see that __hfma2 and __hsub2 exist.
There was a problem hiding this comment.
It might benefit l2_ILP4_half below too
There was a problem hiding this comment.
Good point, though this is not a super simple change. Would have to choose what versions to replace with this (only ILP variants?) and deal with edge cases like odd dimensions. Would also require some re-benchmarking. To avoid making this PR even bigger, would adding at issue for this be better?
There was a problem hiding this comment.
Okay then can you create that issue, and add a comment in the code linking to that issue for better tracking please?
There was a problem hiding this comment.
Created issue #2510 and added comment in code that references it
| __device__ __forceinline__ void l2_fma_sq2(SUMTYPE& acc, float sx, float sy, float2 dst2) | ||
| { | ||
| float dx = sx - dst2.x; | ||
| float dy = sy - dst2.y; | ||
| acc = fmaf(dx, dx, acc); | ||
| acc = fmaf(dy, dy, acc); | ||
| } |
There was a problem hiding this comment.
This might also benefit from fsub2/fmaf2. The data loaded is already float2
|
/ok to test 882b781 |
|
/ok to test f70b984 |
|
/ok to test 0c1a48e |
|
/merge |
Series of GPU Vamana build performance optimizations that addresses #2178 and #1757. Initial estimates from #1757 were not accurate, so many other optimizations were tried (some abandoned, some successful). This PR includes:
GreedySearch optimizations:
RobustPrune optimizations:
General optimizations:
Together these optimizations give significant speedups across all configs with minimal recall variance compared to the current baseline. I benchmarked performance across a range of synthetic datasets and two real-world datasets. (NOTE: finishing benchmarks and will update tables below once they are all collected).
Synthetic dataset build tests (all 1M vector datasets)
Also tested real-world BIGANN 10M (uint8 128D) and GIST (fp32 960D) datasets: