Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add try_unary_mut #3134

Merged
merged 7 commits into from
Nov 28, 2022
Merged

Add try_unary_mut #3134

merged 7 commits into from
Nov 28, 2022

Conversation

viirya
Copy link
Member

@viirya viirya commented Nov 18, 2022

Which issue does this PR close?

Closes #3133.

Rationale for this change

What changes are included in this PR?

Are there any user-facing changes?

@github-actions github-actions bot added the arrow Changes to the arrow crate label Nov 18, 2022
Copy link
Contributor

@tustvold tustvold left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this, I wonder if you have some benchmarks of how this compares to the allocating version, ideally using a modern allocator like jemalloc.

Comment on lines 233 to 237
pub fn as_slice(&mut self) -> (&mut [T::Native], Option<&[u8]>) {
(
self.values_builder.as_slice_mut(),
self.null_buffer_builder.as_slice(),
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn as_slice(&mut self) -> (&mut [T::Native], Option<&[u8]>) {
(
self.values_builder.as_slice_mut(),
self.null_buffer_builder.as_slice(),
)
pub fn slices_mut(&mut self) -> (&mut [T::Native], Option<&mut [u8]>) {
(
self.values_builder.as_slice_mut(),
self.null_buffer_builder.as_slice_mut(),
)

Or something, it seems a bit unusual for both to not be mutable.

We could then add validity_slice and validity_slice_mut for completeness

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, it is because for this I don't need null buffer slice to be mutable. But yes, it looks a bit strange to have one mutable with one non-mutable. 😄

pub fn try_unary_mut<F, E>(
self,
op: F,
) -> Result<PrimitiveArray<T>, Result<PrimitiveArray<T>, E>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
) -> Result<PrimitiveArray<T>, Result<PrimitiveArray<T>, E>>
) -> Result<Result<PrimitiveArray<T>, E>, PrimitiveArray<T>>

I think the reverse result order makes more sense, as it represents the order of fallibility. If we can't convert to a builder is the first error case, then within that we have the error case of ArrowError.

I think it will also make it easier to implement a fallback, e.g.

arr.try_unary_mut(&mut op).unwrap_or_else(|arr| arr.try_unary(&mut op))?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

@@ -150,6 +150,11 @@ impl NullBufferBuilder {
self.bitmap_builder = Some(b);
}
}

#[inline]
pub fn as_slice(&self) -> Option<&[u8]> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Could also add an as_slice_mut for completeness

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea

@viirya
Copy link
Member Author

viirya commented Nov 22, 2022

Thank you for working on this, I wonder if you have some benchmarks of how this compares to the allocating version, ideally using a modern allocator like jemalloc.

Not yet on benchmarking. I think it should be better and hard to think that it could be slower. I will revise this based on above comments and run a benchmark later. Thanks.

@tustvold
Copy link
Contributor

I think it should be better and hard to think that it could be slower

Yeah, I'm just curious as it is a non-trivial additional complexity and so I'm curious what difference it makes 😅

@viirya
Copy link
Member Author

viirya commented Nov 23, 2022

Simply updated slice related functions.

I will update the result type later or tomorrow. (occupied occasionally by other matters in recent days, will be a bit slow response)

@viirya viirya requested a review from tustvold November 27, 2022 03:16
@viirya
Copy link
Member Author

viirya commented Nov 27, 2022

I ran a simple benchmark which calls add or add_mut on two primitive arrays, e.g.,

let mut arr_a = create_primitive_array::<Float32Type>(5120000, 0.0);

for _ in 0..10 {
    let arr_b = create_primitive_array::<Float32Type>(5120000, 0.0);
    // arr_a = add(&arr_a, &arr_b).unwrap();
    arr_a = add_mut(arr_a, &arr_b).unwrap().unwrap();
}
array add               time:   [675.93 ms 676.09 ms 676.28 ms]
                        change: [-3.2262% -3.0312% -2.8816%] (p = 0.00 < 0.05)
                        Performance has improved.

@tustvold
Copy link
Contributor

This seems like quite a lot of additional complexity for only a 3% performance improvement. What do you think about just providing try_unary_mut and leave it at that, just thinking about the number of additional _mut arithmetic kernels this is going to produce? Especially given that most of these kernels would be trivial for a user to implement themselves, should they wish to?

@viirya
Copy link
Member Author

viirya commented Nov 28, 2022

Yeah, thought about this option too. I think it makes sense. I can remove _mut arithmetic kernels and only keep try_unary_mut so we can implement these kernels.

@viirya viirya changed the title Add add_scalar_mut and add_scalar_checked_mut Add try_unary_mut Nov 28, 2022
@@ -285,6 +285,26 @@ impl<T: ArrowPrimitiveType> PrimitiveBuilder<T> {
pub fn values_slice_mut(&mut self) -> &mut [T::Native] {
self.values_builder.as_slice_mut()
}

/// Returns the current values buffer as a slice
#[allow(dead_code)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this shouldn't be necessary, as they are public

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, removed.

@tustvold tustvold merged commit 5d84746 into apache:master Nov 28, 2022
@ursabot
Copy link

ursabot commented Nov 28, 2022

Benchmark runs are scheduled for baseline = 6f41b95 and contender = 5d84746. 5d84746 is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Skipped ⚠️ Benchmarking of arrow-rs-commits is not supported on ec2-t3-xlarge-us-east-2] ec2-t3-xlarge-us-east-2
[Skipped ⚠️ Benchmarking of arrow-rs-commits is not supported on test-mac-arm] test-mac-arm
[Skipped ⚠️ Benchmarking of arrow-rs-commits is not supported on ursa-i9-9960x] ursa-i9-9960x
[Skipped ⚠️ Benchmarking of arrow-rs-commits is not supported on ursa-thinkcentre-m75q] ursa-thinkcentre-m75q
Buildkite builds:
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python, R. Runs only benchmarks with cloud = True
test-mac-arm: Supported benchmark langs: C++, Python, R
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arrow Changes to the arrow crate
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add try_unary_mut
3 participants