-
Notifications
You must be signed in to change notification settings - Fork 4k
ARROW-11627: [Rust] Make allocator be a generic over type T #9495
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
Conversation
|
cc: @sunchao @nevi-me @pitrou @andygrove @alamb, this is a core change to the arrow crate, as it will enable us to allocate memory regions without losing the type information about what they contain. I would appreciate to know if someone sees an issue here. The general direction is stop transmuting byte buffers, which have caused us too many bugs and is AFAIK, this is will also enable us to support multiple endianess, but we are some PRs away from it. For now, we just stick to little endianess (AFAIK we do not support big atm), where at least we make it explicit. cc @maxburke , since you depend on the |
Codecov Report
@@ Coverage Diff @@
## master #9495 +/- ##
==========================================
- Coverage 82.12% 82.05% -0.07%
==========================================
Files 235 236 +1
Lines 54729 54774 +45
==========================================
Hits 44944 44944
- Misses 9785 9830 +45
Continue to review full report at Codecov.
|
alamb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through this carefully and it looks like a significant improvement to me. I would not call myself an expert in this area (low level Rust allocators) but the changes make sense to me.
I vote
@nevi-me or @vertexclique do you have any thoughts about this PR?
rust/arrow/src/alloc/alignment.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW I know you didn't introduce this comment in this PR (it just moved) but I find this comment more confusing than enlightening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've written this before, which part is confusing? Let's rephrase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am overwhelmed by the detail before I get the context of what the information is for.
Maybe if the comment started with something like
// Pick the best memory alignment based on the target architecture.
//
// The rationale for doing so is ....
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// * ptr must denote a block of memory currently allocated via this allocator, | |
| /// * ptr must denote a block of memory previously returned from `allocate_aligned` or | |
| /// `allocate_aligned_zeroed` |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// * ptr must be currently allocated via this allocator, | |
| /// ptr must denote a block of memory previously returned from `allocate_aligned` or | |
| /// `allocate_aligned_zeroed` |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If your allocation size is even anywhere near overflowing a 64-bit usize you are likely going to have problems 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. I do think that this comment applies mostly to 32 bit systems where usize = u32.
rust/arrow/src/alloc/types.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
rust/arrow/src/alloc/types.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// Whether a DataType is a valid type for this physical representation. | |
| /// Whether an array element of `data_type` can be stored using this `NativeType` as | |
| /// its physical representation. For example, `i32` stores `DataType::Int32` as well as | |
| /// `DataType::Date32` |
|
I plan to merge this on the weekend unless I hear any comments otherwise |
|
@jorgecarleitao this needs a rebase :( But then I think we'll (finally) get it in. Woohoo! |
vertexclique
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Atomics needs some improvement and there is no need for SeqCst check since it doesn't matter while test threads are still ongoing. What is needed here is atomicity.
In addition to all these there is a zz_memory_check.rs existing. That code will fail because of ordering is not related to thread access. So I have refactored that for you:
#[cfg(feature = "memory-check")]
mod tests {
use crate::alloc::ALLOCATIONS;
use std::sync::atomic::*;
// verify that there is no data un-allocated
#[test]
fn test_memory_check() {
let mut i: usize = 0;
unsafe {
while ALLOCATIONS.load(Ordering::Relaxed) != 0 {
i+=1;
spin_loop_hint();
// Fair __mm_pause can be 10m.
assert!(i < 10_000_000);
}
}
}
}
rust/arrow/src/alloc/alignment.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've written this before, which part is confusing? Let's rephrase.
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // If this number is not zero after all objects have been `drop`, there is a memory leak | |
| pub static mut ALLOCATIONS: AtomicIsize = AtomicIsize::new(0); | |
| // If this number is not zero after all objects have been `drop`, there is a memory leak | |
| #[cfg(feature = "memory-check")] | |
| pub static mut ALLOCATIONS: AtomicIsize = AtomicIsize::new(0); |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ALLOCATIONS.fetch_add(size as isize, std::sync::atomic::Ordering::SeqCst); | |
| #[cfg(feature = "memory-check")] | |
| ALLOCATIONS.fetch_add(size as isize, Ordering::Relaxed); |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ALLOCATIONS.fetch_add(size as isize, std::sync::atomic::Ordering::SeqCst); | |
| #[cfg(feature = "memory-check")] | |
| ALLOCATIONS.fetch_add(size as isize, Ordering::Relaxed); |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ALLOCATIONS.fetch_sub(size as isize, std::sync::atomic::Ordering::SeqCst); | |
| #[cfg(feature = "memory-check")] | |
| ALLOCATIONS.fetch_sub(size as isize, Ordering::Relaxed); |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ALLOCATIONS.fetch_add( | |
| new_size as isize - old_size as isize, | |
| std::sync::atomic::Ordering::SeqCst, | |
| ); | |
| #[cfg(feature = "memory-check")] | |
| ALLOCATIONS.fetch_add( | |
| new_size.checked_sub(old_size).unwrap() as isize, | |
| Ordering::Relaxed, | |
| ); |
|
@alamb Please don't get it in, it will slow down allocations with MOESI communication between cores. |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| use std::{ | |
| alloc::{handle_alloc_error, Layout}, | |
| sync::atomic::AtomicIsize, | |
| }; | |
| use std::alloc::{handle_alloc_error, Layout}; | |
| use std::sync::atomic::*; |
rust/arrow/src/alloc/mod.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to add the checked_sub check written below for memory-check; also, go here.
rust/arrow/src/alloc/types.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tioli; Adding to_ne_bytes, to_be_bytes would be cool. Why not :)
|
@vertexclique , thanks a lot for going through this and your comments. For my own understanding, could you give some insight into the ordering comments and the Note that this PR does no modify the The change set of this PR is essentially bf1a7eb |
loop hint is for waiting on the cpu without os intervention to wait until to the point of expected value for this test.
I've just seen this, probably I wasn't the reviewer or simply missed the review cycle. |
alamb
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what it is worth, here is a pointer to the ALLOCATIONS code that was moved (aka confirming that the behavior has not changed):
@vertexclique I suggest we get this PR in and then update/optimize the use of ALLOCATIONS as a follow on PR. I think @jorgecarleitao has many other PRs / plans waiting on this PR so we should not delay it unecessairly
rust/arrow/src/alloc/alignment.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am overwhelmed by the detail before I get the context of what the information is for.
Maybe if the comment started with something like
// Pick the best memory alignment based on the target architecture.
//
// The rationale for doing so is ....
|
@alamb @jorgecarleitao @nevi-me Yeah, I am totally ok merging it like this. We can keep track of the suggestions as Jira ticket. :) |
|
FYI: I've assigned these improvements to myself. Truly let's not block each other: https://issues.apache.org/jira/browse/ARROW-11760 @alamb @jorgecarleitao |
|
i've been away for over a week due to personal issues. This PR seems to deal more with the allocator, so not yet necessarily with
I'm fine with getting this PR merged, I'm a bit overwhelmed by the detail, but looking at bf1a7eb has certainly helped me with reviewing the change. |
|
I've rebased, and I'll merge this when CI is green |
|
Thanks @nevi-me |
Thank you @vertexclique ! |
Polars uses the `arrow::memory` module. With the backwards incompatible change of #9495, the API is refactored to `arrow::alloc`. By making `alloc` public, users can shift to the new changes. Closes #9572 from ritchie46/make_alloc_public Authored-by: Ritchie Vink <[email protected]> Signed-off-by: Andrew Lamb <[email protected]>
The background and rational for this is described here; the idea is that this is groundwork to make our buffers typed, so that we can start introducing strong typing in the crate.
This change is backward incompatible:
T: NativeType, which implies that we can now allocate certain types.memoryto a new modulealloc(inspired afterstd::alloc).Necessary steps to migrate existing code:
use arrow::memory->use arrow::allocmemory::allocate_aligned(...)->alloc::allocate_aligned::<u8>(...)Note how
NativeTypecontainsto_le_bytes; we will use this method for IPC, where we need to serialize buffers with a specific endianess. This is ground work to enable multiple endianesses support