Skip to content

Actually use PackedSeq in FlatGFA#241

Open
johnpalsberg wants to merge 62 commits into
mainfrom
john-performance
Open

Actually use PackedSeq in FlatGFA#241
johnpalsberg wants to merge 62 commits into
mainfrom
john-performance

Conversation

@johnpalsberg

Copy link
Copy Markdown
Contributor

Reduces the size of each SeqSpan from 18 bytes to 8 bytes by using u32 indices and logical indices.

@sampsyo sampsyo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Here are a few initial comments on the FlatGFA integration itself! I'll surely have more to say after we do a bit more disentangling of the other stuff from this PR, but this will get us started…

Comment thread flatgfa/src/flatgfa.rs
Comment on lines -3 to +6
use std::ops::Range;
use std::str::FromStr;
//use std::{arch::aarch64::uint8x16x3_t}

use std::ops::Range;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like we can probably revert these changes.

Comment thread flatgfa/src/flatgfa.rs Outdated
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.seq.len()
self.seq.len as usize

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A nice thing to do here might be to provide a len() method, distinct from the len field, that just returns a usize. That would conform to the "usual" pattern for a Rust collection type.

Comment thread flatgfa/src/flatgfa.rs Outdated
// The range starts at the end of the buffer:
// [-----<end<******<start<------]
&self.data[(self.data.len() - range.end)..(self.data.len() - range.start)]
self.data.slice(SeqSpan::from_range(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe it would be nice to create a sibling method to slice in the API that takes a Range instead of a SeqSpan? Just for tidiness in cases like this.

Comment thread flatgfa/src/flatgfa.rs Outdated
pub fn get_seq(&self, seg: &Segment) -> &BStr {
self.seq_data[seg.seq].as_ref()
pub fn get_seq(&self, seg: &Segment) -> PackedSeqView<'_> {
// println!("end {}", seg.seq.end());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like a stray debug thing we can remove.

Comment thread flatgfa/src/flatgfa.rs Outdated
}
}

/// A Span of a packed sequence.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// A Span of a packed sequence.
/// A Span of a packed nucleotide sequence.

Comment thread flatgfa/src/packedseq.rs Outdated

/// Creates a subslice of this PackedSeqView in the range of `span`
pub fn slice(&self, span: SeqSpan) -> Self {
let new_data = &self.data[span.start_byte_index()..span.end_byte_index()];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You could make this kind of code a little simpler to write if, instead of having start_byte_index() and end_byte_index(), you instead had a "bigger" function called byte_range() that returns a Range<usize>.

Comment thread flatgfa/src/flatgfa.rs Outdated
/// A Span of a packed sequence.
#[derive(Debug, FromBytes, IntoBytes, Clone, Copy, PartialEq, Eq, Hash, Immutable)]
#[repr(packed)]
pub struct SeqSpan {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe it would make sense to move SeqSpan to packedseq.rs, just because it is so tightly coupled with the implementation of PackedSeqView?

Comment thread flatgfa/src/flatgfa.rs Outdated
@@ -448,9 +506,37 @@ impl<'a, P: StoreFamily<'a>> GFAStore<'a, P> {

/// Add a new segment to the GFA file.
pub fn add_seg(&mut self, name: usize, seq: &[u8], optional: &[u8]) -> Id<Segment> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think I'd suggest flipping the names of add_seg and add_seg_already_compressed around, to help more obviously convey which is the "cheap one" of the two. We could call it add_seg (for the PackedSeq version) and compress_and_add_seg, for example.

Comment thread flatgfa/src/flatgfa.rs
Comment on lines +516 to +519
seq: SeqSpan {
start,
len: (end - start) as u16,
},

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This would probably be a good place for using that From<Range> impl, if we do it.

Comment thread flatgfa/src/flatgfa.rs Outdated
Comment on lines +509 to +511
let mut compressed: Vec<u8> = Vec::new();
let end_offset = compress_into_buffer(seq, &mut compressed);
let byte_span = self.seq_data.add_slice(&compressed);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It looks like this might entail an extra, possibly-unnecessary copy. That is, we first compress into a new Vec, compressed, then copy that into self.seq_data, and then throw away compressed.

To skip this extra step, would it work to just use compress_into_buffer on seq_data, and possibly extend that API to provide enough of a result?

This was referenced Jan 8, 2026
@sampsyo sampsyo changed the title Reduce SeqSpan size Actually use PackedSeq in FlatGFA Jan 9, 2026
@sampsyo

sampsyo commented Jan 9, 2026

Copy link
Copy Markdown
Collaborator

I retitled this to better reflect is role as the successor to #214.

@sampsyo sampsyo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just marking a few items in the current PR that should be split off into a separate, performance-measurement-focused PR.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this belongs in a separate benchmarking PR.

Comment thread bench/__init__.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks like diff noise?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's revert this whitespace change.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The stuff in tests/performance/ also belongs in a separate performance-measurement PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants