Skip to content

Commit 55fa419

Browse files
committed
fix: use T aligned pointer in TempFdArray
1 parent 4939f73 commit 55fa419

File tree

2 files changed

+48
-18
lines changed

2 files changed

+48
-18
lines changed

src/collector.rs

+44-16
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::convert::TryInto;
55
use std::fmt::Debug;
66
use std::hash::{Hash, Hasher};
77
use std::io::{Read, Seek, SeekFrom, Write};
8+
use std::mem::ManuallyDrop;
89

910
use crate::frames::UnresolvedFrames;
1011

@@ -148,6 +149,7 @@ pub struct TempFdArray<T: 'static> {
148149
file: NamedTempFile,
149150
buffer: Box<[T; BUFFER_LENGTH]>,
150151
buffer_index: usize,
152+
flush_n: usize,
151153
}
152154

153155
impl<T: Default + Debug> TempFdArray<T> {
@@ -162,6 +164,7 @@ impl<T: Default + Debug> TempFdArray<T> {
162164
file,
163165
buffer,
164166
buffer_index: 0,
167+
flush_n: 0,
165168
})
166169
}
167170
}
@@ -175,6 +178,7 @@ impl<T> TempFdArray<T> {
175178
BUFFER_LENGTH * std::mem::size_of::<T>(),
176179
)
177180
};
181+
self.flush_n += 1;
178182
self.file.write_all(buf)?;
179183

180184
Ok(())
@@ -191,24 +195,50 @@ impl<T> TempFdArray<T> {
191195
Ok(())
192196
}
193197

194-
fn try_iter(&self) -> std::io::Result<impl Iterator<Item = &T>> {
195-
let mut file_vec = Vec::new();
196-
let mut file = self.file.reopen()?;
197-
file.seek(SeekFrom::Start(0))?;
198-
file.read_to_end(&mut file_vec)?;
199-
file.seek(SeekFrom::End(0))?;
198+
fn try_iter<'lt>(&'lt self, file_buffer_container: &'lt mut Option<Box<[ManuallyDrop<T>]>>) -> std::io::Result<impl Iterator<Item = &'lt T>> {
199+
let file_buffer = self.file_buffer()?;
200+
let file_buffer = file_buffer_container.insert(file_buffer);
200201

201202
Ok(TempFdArrayIterator {
202203
buffer: &self.buffer[0..self.buffer_index],
203-
file_vec,
204+
file_buffer,
204205
index: 0,
205206
})
206207
}
208+
209+
fn file_buffer(&self) -> std::io::Result<Box<[ManuallyDrop<T>]>> {
210+
if self.flush_n == 0 {
211+
return Ok(Vec::new().into_boxed_slice())
212+
}
213+
214+
let mut file = self.file.reopen()?;
215+
file.seek(SeekFrom::Start(0))?;
216+
let file_buffer = unsafe {
217+
// Get properly aligned pointer
218+
let len = BUFFER_LENGTH * self.flush_n;
219+
// Expect T to be non-ZST
220+
let layout = std::alloc::Layout::array::<ManuallyDrop<T>>(len).unwrap();
221+
let ptr = std::alloc::alloc(layout);
222+
if ptr.is_null() {
223+
std::alloc::handle_alloc_error(layout);
224+
}
225+
// Populate with bytes
226+
file.read_exact(std::slice::from_raw_parts_mut(
227+
ptr,
228+
len * std::mem::size_of::<T>(),
229+
))?;
230+
// Cast to proper type
231+
Box::from_raw(std::ptr::slice_from_raw_parts_mut(ptr.cast::<ManuallyDrop<T>>(), len))
232+
};
233+
file.seek(SeekFrom::End(0))?;
234+
235+
Ok(file_buffer)
236+
}
207237
}
208238

209239
pub struct TempFdArrayIterator<'a, T> {
210240
pub buffer: &'a [T],
211-
pub file_vec: Vec<u8>,
241+
pub file_buffer: &'a [ManuallyDrop<T>],
212242
pub index: usize,
213243
}
214244

@@ -220,12 +250,9 @@ impl<'a, T> Iterator for TempFdArrayIterator<'a, T> {
220250
self.index += 1;
221251
Some(&self.buffer[self.index - 1])
222252
} else {
223-
let length = self.file_vec.len() / std::mem::size_of::<T>();
224-
let ts =
225-
unsafe { std::slice::from_raw_parts(self.file_vec.as_ptr() as *const T, length) };
226-
if self.index - self.buffer.len() < ts.len() {
253+
if self.index - self.buffer.len() < self.file_buffer.len() {
227254
self.index += 1;
228-
Some(&ts[self.index - self.buffer.len() - 1])
255+
Some(&self.file_buffer[self.index - self.buffer.len() - 1])
229256
} else {
230257
None
231258
}
@@ -256,8 +283,8 @@ impl<T: Hash + Eq + 'static> Collector<T> {
256283
Ok(())
257284
}
258285

259-
pub fn try_iter(&self) -> std::io::Result<impl Iterator<Item = &Entry<T>>> {
260-
Ok(self.map.iter().chain(self.temp_array.try_iter()?))
286+
pub fn try_iter<'lt>(&'lt self, file_buffer_store: &'lt mut Option<Box<[ManuallyDrop<Entry<T>>]>>) -> std::io::Result<impl Iterator<Item = &'lt Entry<T>>> {
287+
Ok(self.map.iter().chain(self.temp_array.try_iter(file_buffer_store)?))
261288
}
262289
}
263290

@@ -343,7 +370,8 @@ mod tests {
343370
}
344371
}
345372

346-
collector.try_iter().unwrap().for_each(|entry| {
373+
let mut file_buffer_store = None;
374+
collector.try_iter(&mut file_buffer_store).unwrap().for_each(|entry| {
347375
test_utils::add_map(&mut real_map, entry);
348376
});
349377

src/report.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ impl<'a> ReportBuilder<'a> {
6969
Err(Error::CreatingError)
7070
}
7171
Ok(profiler) => {
72-
profiler.data.try_iter()?.for_each(|entry| {
72+
let mut file_buffer_store = None;
73+
profiler.data.try_iter(&mut file_buffer_store)?.for_each(|entry| {
7374
let count = entry.count;
7475
if count > 0 {
7576
let key = &entry.item;
@@ -107,7 +108,8 @@ impl<'a> ReportBuilder<'a> {
107108
Err(Error::CreatingError)
108109
}
109110
Ok(profiler) => {
110-
profiler.data.try_iter()?.for_each(|entry| {
111+
let mut file_buffer_store = None;
112+
profiler.data.try_iter(&mut file_buffer_store)?.for_each(|entry| {
111113
let count = entry.count;
112114
if count > 0 {
113115
let mut key = Frames::from(entry.item.clone());

0 commit comments

Comments
 (0)