@@ -24,19 +24,6 @@ use crate::leaf_build;
2424use crate :: partition:: { self , PartitionConfig } ;
2525use crate :: { PiPNNConfig , PiPNNError , PiPNNResult } ;
2626
27- /// Ask glibc to return freed pages to the OS.
28- /// Without this, RSS stays inflated after large temporary allocations
29- /// (e.g. partition GEMM buffers) even though the memory is freed.
30- #[ cfg( target_os = "linux" ) ]
31- fn trim_heap ( ) {
32- unsafe {
33- extern "C" { fn malloc_trim ( pad : usize ) -> i32 ; }
34- malloc_trim ( 0 ) ;
35- }
36- }
37-
38- #[ cfg( not( target_os = "linux" ) ) ]
39- fn trim_heap ( ) { }
4027
4128
4229use diskann_vector:: distance:: { Distance , DistanceProvider , Metric } ;
@@ -264,11 +251,6 @@ impl PiPNNGraph {
264251/// matching DiskANN's `find_medoid_with_sampling` behavior. The centroid
265252/// is a geometric center, so L2 is the natural metric regardless of the
266253/// build distance metric.
267- /// Public wrapper for find_medoid, used by diskann-disk's build pipeline.
268- pub fn find_medoid_public < T : VectorRepr > ( data : & [ T ] , npoints : usize , ndims : usize ) -> usize {
269- find_medoid ( data, npoints, ndims)
270- }
271-
272254fn find_medoid < T : VectorRepr > ( data : & [ T ] , npoints : usize , ndims : usize ) -> usize {
273255 let dist_fn = make_dist_fn ( Metric :: L2 ) ;
274256
@@ -302,8 +284,8 @@ fn find_medoid<T: VectorRepr>(data: &[T], npoints: usize, ndims: usize) -> usize
302284
303285/// Build a PiPNN index from typed vector data.
304286///
305- /// Keeps data in its native type T and converts to f32 on-the-fly at each access point.
306- /// For f16 data this saves ~793 MB peak RSS compared to upfront conversion .
287+ /// Keeps data in its native type T and converts to f32 on-the-fly at each access point,
288+ /// avoiding a full f32 copy of the dataset .
307289/// `data` is a flat slice of `T` in row-major order: npoints x ndims.
308290pub fn build_typed < T : VectorRepr + Send + Sync > (
309291 data : & [ T ] ,
@@ -450,13 +432,11 @@ pub fn build_with_sq<T: VectorRepr + Send + Sync>(
450432 build_internal_sq ( npoints, ndims, config, qdata, sketches, medoid)
451433}
452434
453- /// SQ build path: f32 data already dropped, using pre-computed sketches.
454- /// Saves ~1.6 GB peak memory by not holding f32 alongside HashPrune reservoirs.
455435/// Build a PiPNN index from pre-quantized data + pre-computed medoid.
456436///
457437/// Lowest-memory entry point for SQ builds: the caller quantizes and computes
458438/// medoid, then drops native data before calling this. Only the 1-bit quantized
459- /// data (~48 MB for 1M×384d) needs to be in memory during the graph build.
439+ /// data needs to be in memory during the graph build.
460440pub fn build_from_quantized (
461441 qdata : crate :: quantize:: QuantizedData ,
462442 npoints : usize ,
@@ -557,7 +537,6 @@ fn build_internal_sq_impl(
557537 let ( adjacency, extract_secs, final_prune_secs) = if config. final_prune {
558538 let candidates = hash_prune. extract_graph_for_prune ( ) ;
559539 let extract_secs = t3. elapsed ( ) . as_secs_f64 ( ) ;
560- trim_heap ( ) ;
561540 // final_prune needs f32 data which we don't have — fall back to no-prune.
562541 // (final_prune_from_candidates requires T: VectorRepr for distance recomputation)
563542 tracing:: warn!( "final_prune=true with SQ build: pruning skipped (no f32 data)" ) ;
@@ -568,7 +547,6 @@ fn build_internal_sq_impl(
568547 } else {
569548 let adj = hash_prune. extract_graph ( ) ;
570549 let extract_secs = t3. elapsed ( ) . as_secs_f64 ( ) ;
571- trim_heap ( ) ;
572550 ( adj, extract_secs, 0.0 )
573551 } ;
574552
@@ -670,9 +648,7 @@ fn build_internal_impl<T: VectorRepr + Send + Sync>(
670648 total_pts = total_pts,
671649 "Partition complete"
672650 ) ;
673- // Return freed partition GEMM buffers to the OS so they don't inflate
674- // peak RSS during the subsequent leaf build + reservoir filling phase.
675- trim_heap ( ) ;
651+ // Hint to return freed partition GEMM buffers to the OS.
676652 tracing:: debug!(
677653 small_leaves = small_leaves,
678654 med_leaves = med_leaves,
@@ -721,7 +697,6 @@ fn build_internal_impl<T: VectorRepr + Send + Sync>(
721697 let candidates = hash_prune. extract_graph_for_prune ( ) ;
722698 let extract_secs = t3. elapsed ( ) . as_secs_f64 ( ) ;
723699 tracing:: info!( elapsed_secs = extract_secs, "Graph extraction complete (full reservoir)" ) ;
724- trim_heap ( ) ;
725700
726701 let t4 = Instant :: now ( ) ;
727702 tracing:: info!( "Applying final prune (selecting {} from {} candidates)" , config. max_degree, config. l_max) ;
@@ -733,7 +708,6 @@ fn build_internal_impl<T: VectorRepr + Send + Sync>(
733708 let adj = hash_prune. extract_graph ( ) ;
734709 let extract_secs = t3. elapsed ( ) . as_secs_f64 ( ) ;
735710 tracing:: info!( elapsed_secs = extract_secs, "Graph extraction complete" ) ;
736- trim_heap ( ) ;
737711 ( adj, extract_secs, 0.0 )
738712 } ;
739713
@@ -761,7 +735,6 @@ fn build_internal_impl<T: VectorRepr + Send + Sync>(
761735
762736 // Return all freed memory (reservoirs, sketches, partition buffers, leaf buffers)
763737 // to the OS before handing off to the disk layout phase.
764- trim_heap ( ) ;
765738
766739 tracing:: info!(
767740 avg_degree = graph. avg_degree( ) ,
0 commit comments