Skip to content

Commit 3a8fa2c

Browse files
authored
perf: Eliminate several copies from C to rust (#293)
* metadata decoding no longer makes an extra copy * ancestral/derived states of sites/mutations no longer make extra copies. BREAKING CHANGE: return types of SiteTable::ancestral_state and MutationTable:derived_state now return slices instead of vectors.
1 parent 8698247 commit 3a8fa2c

File tree

9 files changed

+53
-46
lines changed

9 files changed

+53
-46
lines changed

src/_macros.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ macro_rules! build_tskit_type {
173173
}
174174

175175
macro_rules! metadata_to_vector {
176-
($table: expr, $row: expr) => {
177-
$crate::metadata::char_column_to_vector(
176+
($outer: ident, $table: expr, $row: expr) => {
177+
$crate::metadata::char_column_to_slice(
178+
$outer,
178179
$table.metadata,
179180
$table.metadata_offset,
180181
$row,
@@ -196,8 +197,10 @@ macro_rules! decode_metadata_row {
196197
}
197198

198199
macro_rules! table_row_decode_metadata {
199-
($table: ident, $pos: ident) => {
200-
metadata_to_vector!($table, $pos).unwrap().map(|x| x)
200+
($owner: ident, $table: ident, $pos: ident) => {
201+
metadata_to_vector!($owner, $table, $pos)
202+
.unwrap()
203+
.map(|x| x)
201204
};
202205
}
203206

src/edge_table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn make_edge_table_row(table: &EdgeTable, pos: tsk_id_t) -> Option<EdgeTableRow>
3939
right: table.right(pos).unwrap(),
4040
parent: table.parent(pos).unwrap(),
4141
child: table.child(pos).unwrap(),
42-
metadata: table_row_decode_metadata!(table_ref, pos),
42+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
4343
};
4444
Some(rv)
4545
} else {
@@ -141,7 +141,7 @@ impl<'a> EdgeTable<'a> {
141141
row: EdgeId,
142142
) -> Result<Option<T>, TskitError> {
143143
let table_ref = self.table_;
144-
let buffer = metadata_to_vector!(table_ref, row.0)?;
144+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
145145
decode_metadata_row!(T, buffer)
146146
}
147147

src/individual_table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn make_individual_table_row(table: &IndividualTable, pos: tsk_id_t) -> Option<I
6363
flags: table.flags(pos).unwrap(),
6464
location: table.location(pos).unwrap().map(|s| s.to_vec()),
6565
parents: table.parents(pos).unwrap().map(|s| s.to_vec()),
66-
metadata: table_row_decode_metadata!(table_ref, pos),
66+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
6767
};
6868
Some(rv)
6969
} else {
@@ -248,7 +248,7 @@ impl<'a> IndividualTable<'a> {
248248
row: IndividualId,
249249
) -> Result<Option<T>, TskitError> {
250250
let table_ref = self.table_;
251-
let buffer = metadata_to_vector!(table_ref, row.0)?;
251+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
252252
decode_metadata_row!(T, buffer)
253253
}
254254

src/metadata.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -250,13 +250,14 @@ pub enum MetadataError {
250250
},
251251
}
252252

253-
pub(crate) fn char_column_to_vector(
253+
pub(crate) fn char_column_to_slice<T: Sized>(
254+
_lifetime: &T,
254255
column: *const libc::c_char,
255256
column_offset: *const tsk_size_t,
256257
row: tsk_id_t,
257258
num_rows: tsk_size_t,
258259
column_length: tsk_size_t,
259-
) -> Result<Option<Vec<u8>>, crate::TskitError> {
260+
) -> Result<Option<&[u8]>, crate::TskitError> {
260261
let row = match tsk_size_t::try_from(row) {
261262
Ok(r) => r,
262263
Err(_) => return Err(TskitError::IndexError),
@@ -288,23 +289,27 @@ pub(crate) fn char_column_to_vector(
288289
if column_length == 0 {
289290
return Ok(None);
290291
}
291-
let mut buffer = vec![];
292-
for i in start..stop {
293-
match isize::try_from(i) {
294-
// NOTE: cast_sign_loss pedantic lint is a false +ve here.
295-
// The metadata live as C strings on the tskit-C side, so
296-
// the integer cast exists as part of the round trip.
297-
#[allow(clippy::cast_sign_loss)]
298-
Ok(o) => buffer.push(unsafe { *column.offset(o) } as u8),
299-
Err(_) => {
300-
return Err(TskitError::RangeError(format!(
301-
"cauld not convert value {} to isize",
302-
stringify!(i)
303-
)))
304-
}
305-
};
306-
}
307-
Ok(Some(buffer))
292+
let istart = match isize::try_from(start) {
293+
Ok(v) => v,
294+
Err(_) => {
295+
return Err(TskitError::RangeError(format!(
296+
"cauld not convert value {} to isize",
297+
stringify!(i)
298+
)));
299+
}
300+
};
301+
let ustop = match usize::try_from(stop) {
302+
Ok(v) => v,
303+
Err(_) => {
304+
return Err(TskitError::RangeError(format!(
305+
"cauld not convert value {} to usize",
306+
stringify!(i)
307+
)));
308+
}
309+
};
310+
Ok(Some(unsafe {
311+
std::slice::from_raw_parts(column.offset(istart) as *const u8, ustop - istart as usize)
312+
}))
308313
}
309314

310315
#[cfg(test)]

src/migration_table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn make_migration_table_row(table: &MigrationTable, pos: tsk_id_t) -> Option<Mig
4747
source: table.source(pos).unwrap(),
4848
dest: table.dest(pos).unwrap(),
4949
time: table.time(pos).unwrap(),
50-
metadata: table_row_decode_metadata!(table_ref, pos),
50+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
5151
})
5252
} else {
5353
None
@@ -186,7 +186,7 @@ impl<'a> MigrationTable<'a> {
186186
row: MigrationId,
187187
) -> Result<Option<T>, TskitError> {
188188
let table_ref = self.table_;
189-
let buffer = metadata_to_vector!(table_ref, row.0)?;
189+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
190190
decode_metadata_row!(T, buffer)
191191
}
192192

src/mutation_table.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ fn make_mutation_table_row(table: &MutationTable, pos: tsk_id_t) -> Option<Mutat
4242
node: table.node(pos).unwrap(),
4343
parent: table.parent(pos).unwrap(),
4444
time: table.time(pos).unwrap(),
45-
derived_state: table.derived_state(pos).unwrap(),
46-
metadata: table_row_decode_metadata!(table_ref, pos),
45+
derived_state: table.derived_state(pos).unwrap().map(|s| s.to_vec()),
46+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
4747
};
4848
Some(rv)
4949
} else {
@@ -155,8 +155,9 @@ impl<'a> MutationTable<'a> {
155155
pub fn derived_state<M: Into<MutationId>>(
156156
&'a self,
157157
row: M,
158-
) -> Result<Option<Vec<u8>>, TskitError> {
159-
metadata::char_column_to_vector(
158+
) -> Result<Option<&[u8]>, TskitError> {
159+
metadata::char_column_to_slice(
160+
self,
160161
self.table_.derived_state,
161162
self.table_.derived_state_offset,
162163
row.into().0,
@@ -170,7 +171,7 @@ impl<'a> MutationTable<'a> {
170171
row: MutationId,
171172
) -> Result<Option<T>, TskitError> {
172173
let table_ref = self.table_;
173-
let buffer = metadata_to_vector!(table_ref, row.0)?;
174+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
174175
decode_metadata_row!(T, buffer)
175176
}
176177

src/node_table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn make_node_table_row(table: &NodeTable, pos: tsk_id_t) -> Option<NodeTableRow>
4141
flags: table.flags(pos).unwrap(),
4242
population: table.population(pos).unwrap(),
4343
individual: table.individual(pos).unwrap(),
44-
metadata: table_row_decode_metadata!(table_ref, pos),
44+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
4545
})
4646
} else {
4747
None
@@ -189,7 +189,7 @@ impl<'a> NodeTable<'a> {
189189
row: NodeId,
190190
) -> Result<Option<T>, TskitError> {
191191
let table_ref = self.table_;
192-
let buffer = metadata_to_vector!(table_ref, row.0)?;
192+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
193193
decode_metadata_row!(T, buffer)
194194
}
195195

src/population_table.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ fn make_population_table_row(table: &PopulationTable, pos: tsk_id_t) -> Option<P
2828
let table_ref = table.table_;
2929
let rv = PopulationTableRow {
3030
id: pos.into(),
31-
metadata: table_row_decode_metadata!(table_ref, pos),
31+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
3232
};
3333
Some(rv)
3434
} else {
@@ -86,7 +86,7 @@ impl<'a> PopulationTable<'a> {
8686
row: PopulationId,
8787
) -> Result<Option<T>, TskitError> {
8888
let table_ref = self.table_;
89-
let buffer = metadata_to_vector!(table_ref, row.0)?;
89+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
9090
decode_metadata_row!(T, buffer)
9191
}
9292

src/site_table.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ fn make_site_table_row(table: &SiteTable, pos: tsk_id_t) -> Option<SiteTableRow>
3434
let rv = SiteTableRow {
3535
id: pos.into(),
3636
position: table.position(pos).unwrap(),
37-
ancestral_state: table.ancestral_state(pos).unwrap(),
38-
metadata: table_row_decode_metadata!(table_ref, pos),
37+
ancestral_state: table.ancestral_state(pos).unwrap().map(|s| s.to_vec()),
38+
metadata: table_row_decode_metadata!(table, table_ref, pos).map(|m| m.to_vec()),
3939
};
4040
Some(rv)
4141
} else {
@@ -108,11 +108,9 @@ impl<'a> SiteTable<'a> {
108108
///
109109
/// Will return [``IndexError``](crate::TskitError::IndexError)
110110
/// if ``row`` is out of range.
111-
pub fn ancestral_state<S: Into<SiteId>>(
112-
&'a self,
113-
row: S,
114-
) -> Result<Option<Vec<u8>>, TskitError> {
115-
crate::metadata::char_column_to_vector(
111+
pub fn ancestral_state<S: Into<SiteId>>(&'a self, row: S) -> Result<Option<&[u8]>, TskitError> {
112+
crate::metadata::char_column_to_slice(
113+
self,
116114
self.table_.ancestral_state,
117115
self.table_.ancestral_state_offset,
118116
row.into().0,
@@ -126,7 +124,7 @@ impl<'a> SiteTable<'a> {
126124
row: SiteId,
127125
) -> Result<Option<T>, TskitError> {
128126
let table_ref = self.table_;
129-
let buffer = metadata_to_vector!(table_ref, row.0)?;
127+
let buffer = metadata_to_vector!(self, table_ref, row.0)?;
130128
decode_metadata_row!(T, buffer)
131129
}
132130

0 commit comments

Comments
 (0)