Skip to content

Commit 7bab606

Browse files
authored
Merge pull request #1 from alamb/alamb/fix_gc
Try and improve GC performance
2 parents fdefa5f + a962382 commit 7bab606

File tree

1 file changed

+58
-44
lines changed

1 file changed

+58
-44
lines changed

arrow-array/src/array/byte_view_array.rs

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -512,18 +512,36 @@ impl<T: ByteViewType + ?Sized> GenericByteViewArray<T> {
512512
};
513513
}
514514

515-
struct GcCopyGroup {
516-
total_buffer_bytes: usize,
517-
total_len: usize,
518-
}
515+
let (views_buf, data_blocks) = if total_large < i32::MAX as usize {
516+
// fast path, the entire data fits in a single buffer
517+
// 3) Allocate exactly capacity for all non-inline data
518+
let mut data_buf = Vec::with_capacity(total_large);
519+
520+
// 4) Iterate over views and process each inline/non-inline view
521+
let views_buf: Vec<u128> = (0..len)
522+
.map(|i| unsafe { self.copy_view_to_buffer(i, 0, &mut data_buf) })
523+
.collect();
524+
let data_block = Buffer::from_vec(data_buf);
525+
let data_blocks = vec![data_block];
526+
(views_buf, data_blocks)
527+
} else {
528+
// slow path, need to split into multiple buffers
529+
530+
struct GcCopyGroup {
531+
total_buffer_bytes: usize,
532+
total_len: usize,
533+
}
534+
535+
impl GcCopyGroup {
536+
fn new(total_buffer_bytes: u32, total_len: usize) -> Self {
537+
Self {
538+
total_buffer_bytes: total_buffer_bytes as usize,
539+
total_len,
540+
}
541+
}
542+
}
519543

520-
let mut groups = vec![];
521-
let one_group = [GcCopyGroup {
522-
total_buffer_bytes: total_large,
523-
total_len: len,
524-
}];
525-
let gc_copy_groups = if total_large > i32::MAX as usize {
526-
// Slow-path: need to split into multiple copy groups
544+
let mut groups = Vec::with_capacity(total_large / (i32::MAX as usize) + 1);
527545
let mut current_length = 0;
528546
let mut current_elements = 0;
529547

@@ -532,10 +550,7 @@ impl<T: ByteViewType + ?Sized> GenericByteViewArray<T> {
532550
if len > MAX_INLINE_VIEW_LEN {
533551
if current_length + len > i32::MAX as u32 {
534552
// Start a new group
535-
groups.push(GcCopyGroup {
536-
total_buffer_bytes: current_length as usize,
537-
total_len: current_elements,
538-
});
553+
groups.push(GcCopyGroup::new(current_length, current_elements));
539554
current_length = 0;
540555
current_elements = 0;
541556
}
@@ -544,38 +559,37 @@ impl<T: ByteViewType + ?Sized> GenericByteViewArray<T> {
544559
}
545560
}
546561
if current_elements != 0 {
547-
groups.push(GcCopyGroup {
548-
total_buffer_bytes: current_length as usize,
549-
total_len: current_elements,
550-
});
562+
groups.push(GcCopyGroup::new(current_length, current_elements));
551563
}
552-
&groups
553-
} else {
554-
one_group.as_slice()
555-
};
556-
debug_assert!(gc_copy_groups.len() <= i32::MAX as usize);
557-
558-
// 3) Copy the buffers group by group
559-
let mut views_buf = Vec::with_capacity(len);
560-
let mut data_blocks = Vec::with_capacity(gc_copy_groups.len());
561-
562-
let mut current_view_idx = 0;
563-
564-
for (group_idx, gc_copy_group) in gc_copy_groups.iter().enumerate() {
565-
let mut data_buf = Vec::with_capacity(gc_copy_group.total_buffer_bytes);
566-
567-
// Directly push views to avoid intermediate Vec allocation
568-
for view_idx in current_view_idx..current_view_idx + gc_copy_group.total_len {
569-
let view =
570-
unsafe { self.copy_view_to_buffer(view_idx, group_idx as i32, &mut data_buf) };
571-
views_buf.push(view);
564+
debug_assert!(groups.len() <= i32::MAX as usize);
565+
566+
// 3) Copy the buffers group by group
567+
let mut views_buf = Vec::with_capacity(len);
568+
let mut data_blocks = Vec::with_capacity(groups.len());
569+
570+
let mut current_view_idx = 0;
571+
572+
for (group_idx, gc_copy_group) in groups.iter().enumerate() {
573+
let mut data_buf = Vec::with_capacity(gc_copy_group.total_buffer_bytes);
574+
575+
// Directly push views to avoid intermediate Vec allocation
576+
let new_views = (current_view_idx..current_view_idx + gc_copy_group.total_len).map(
577+
|view_idx| {
578+
// safety: the view index came from iterating over valid range
579+
unsafe {
580+
self.copy_view_to_buffer(view_idx, group_idx as i32, &mut data_buf)
581+
}
582+
},
583+
);
584+
views_buf.extend(new_views);
585+
586+
data_blocks.push(Buffer::from_vec(data_buf));
587+
current_view_idx += gc_copy_group.total_len;
572588
}
589+
(views_buf, data_blocks)
590+
};
573591

574-
data_blocks.push(Buffer::from_vec(data_buf));
575-
current_view_idx += gc_copy_group.total_len;
576-
}
577-
578-
// 4) Wrap up buffers
592+
// 5) Wrap up buffers
579593
let views_scalar = ScalarBuffer::from(views_buf);
580594

581595
// SAFETY: views_scalar, data_blocks, and nulls are correctly aligned and sized

0 commit comments

Comments
 (0)