-
Notifications
You must be signed in to change notification settings - Fork 465
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
Support lgalloc for columnar #31230
base: main
Are you sure you want to change the base?
Support lgalloc for columnar #31230
Conversation
Adds support for allocating memory for columnar's aligned type from lgalloc. Adds a flag `enable_lgalloc_columnar` to control the behavior. Signed-off-by: Moritz Hoffmann <[email protected]> # Conflicts: # src/compute/src/logging/differential.rs # src/compute/src/logging/initialize.rs # src/compute/src/logging/reachability.rs Signed-off-by: Moritz Hoffmann <[email protected]>
6355228
to
2fb406a
Compare
/// Allocate a region of memory with a capacity of at least `len` that is aligned to 8 bytes | ||
/// and zeroed. | ||
#[inline] | ||
pub(crate) fn alloc_aligned_zeroed(len: usize) -> Region<u64> { | ||
if enable_lgalloc_columnar() { | ||
Region::new_auto_zeroed(len) | ||
} else { | ||
Region::new_heap_zeroed(len) | ||
} | ||
} |
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.
Mind adding to this comment that it's aligned to 8 bytes because it's a Region of u64
s?
assert!(align <= 8); | ||
let length = u64::cast_from(bytes.len()); | ||
let length_slice = bytemuck::cast_slice(std::slice::from_ref(&length)); | ||
writer.write_all(length_slice).unwrap(); | ||
writer.write_all(bytes).unwrap(); | ||
let padding = usize::cast_from((8 - (length % 8)) % 8); | ||
writer.write_all(&[0; 8][..padding]).unwrap(); |
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'm not totally up-to-date on the encoded layout of a Column
, but my read is this layouts data like:
<u64 encoded in native endianness><buffer whose length is the u64><optional padding>
If that's what it's supposed to do then it LGTM!
pub const ENABLE_LGALLOC_COLUMNAR: Config<bool> = Config::new( | ||
"enable_lgalloc_columnar", |
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.
Nit: Call this enable_columnar_lgalloc
for consistency with the columniation flag?
pub const ENABLE_LGALLOC_COLUMNAR: Config<bool> = Config::new( | ||
"enable_lgalloc_columnar", | ||
true, | ||
"Enable allocating alignd regions in columnar from lgalloc.", |
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.
"Enable allocating alignd regions in columnar from lgalloc.", | |
"Enable allocating aligned regions in columnar from lgalloc.", |
} | ||
} | ||
// Fall-through | ||
Region::Heap(vec![0; capacity]) |
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.
Region::Heap(vec![0; capacity]) | |
Self::new_heap_zeroed(capacity) |
use timely::bytes::arc::Bytes; | ||
use timely::container::PushInto; | ||
use timely::dataflow::channels::ContainerBytes; | ||
use timely::Container; | ||
|
||
use crate::containers::alloc_aligned_zeroed; |
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.
Isn't this import redundant, since it's importing from the current module?
pub fn new_mmap_zeroed(capacity: usize) -> Result<Region<u64>, lgalloc::AllocError> { | ||
lgalloc::allocate::<u64>(capacity).map(|(ptr, capacity, handle)| { | ||
// SAFETY: `allocate` returns a valid memory block | ||
unsafe { ptr.as_ptr().write_bytes(0, capacity) } |
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.
This seems like something that could introduce performance regressions once we start switching more things from columnation to columnar. Is the zeroing required for columnar to work?
use timely::container::PushInto; | ||
use timely::container::{ContainerBuilder, LengthPreservingContainerBuilder}; | ||
|
||
use super::Column; | ||
|
||
thread_local! { | ||
static ENABLE_LGALLOC_COLUMNAR: std::cell::RefCell<bool> = const { std::cell::RefCell::new(false) }; |
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.
static ENABLE_LGALLOC_COLUMNAR: std::cell::RefCell<bool> = const { std::cell::RefCell::new(false) }; | |
static ENABLE_LGALLOC_COLUMNAR: std::cell::RefCell<bool> = std::cell::RefCell::new(false); |
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.
You could also use an AtomicBool
here, to rule out the possibility of panics.
let length = u64::cast_from(bytes.len()); | ||
let length_slice = bytemuck::cast_slice(std::slice::from_ref(&length)); | ||
writer.write_all(length_slice).unwrap(); | ||
writer.write_all(bytes).unwrap(); | ||
let padding = usize::cast_from((8 - (length % 8)) % 8); | ||
writer.write_all(&[0; 8][..padding]).unwrap(); |
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.
Is there a columnar
method we could invoke so we don't have to worry about this code diverging from the columnar
implementation?
// SAFETY: casting `elements` to a `*const [T]` is safe since the caller guarantees that | ||
// `slice` is initialized, and `MaybeUninit` is guaranteed to have the same layout as `T`. | ||
// The pointer obtained is valid since it refers to memory owned by `elements` which is a | ||
// reference and thus guaranteed to be valid for reads. |
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.
This safety argument talks about *const
and reads, but we're casting to a *mut
and deference that for writes. I think a similar argument still holds, based on that elements
is mutably borrowed here, so we can produce a &mut
into it.
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.
Seems good, though there are a few moments I'm not entirely clear on. But structurally the PR seems ok!
@@ -342,6 +344,48 @@ impl<T> Region<T> { | |||
} | |||
} | |||
|
|||
impl Region<u64> { |
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.
Does this exist because of columnar's u64
bias? If so, is this great news and we love it, or is this a work around and we're not happy? Mostly trying to grok what's going on here and for what reason, which I imagine is clearer to you than it is to me.
@@ -120,6 +128,22 @@ impl<T> Deref for Array<T> { | |||
} | |||
} | |||
|
|||
impl<T> DerefMut for Array<T> { | |||
fn deref_mut(&mut self) -> &mut Self::Target { | |||
// TODO: Use `slice_assume_init_ref` once stable. |
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.
Probably slice_assume_init_mut
rather than _ref
, I think?
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 nothing else, we'll want to have the unsafe
justification for _mut
instead, I think. Maybe a nit, but "have the right explanation when we use unsafe" seems like a great place to pick nits.
Adds support for allocating memory for columnar's aligned type from
lgalloc. Adds a flag
enable_lgalloc_columnar
to control the behavior.Checklist
$T ⇔ Proto$T
mapping (possibly in a backwards-incompatible way), then it is tagged with aT-proto
label.