Skip to content

Commit b1d02fd

Browse files
authored
fix alignment issue in collector (#255)
Signed-off-by: Yang Keao <[email protected]>
1 parent 4939f73 commit b1d02fd

File tree

7 files changed

+144
-14
lines changed

7 files changed

+144
-14
lines changed

.github/workflows/rust.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
uses: actions-rs/[email protected]
2020
with:
2121
profile: minimal
22-
toolchain: 1.64.0
22+
toolchain: 1.66.0
2323
override: true
2424
components: rustfmt, clippy
2525

@@ -56,7 +56,7 @@ jobs:
5656
strategy:
5757
matrix:
5858
os: [ubuntu-latest, macos-latest]
59-
toolchain: [stable, nightly, 1.64.0]
59+
toolchain: [stable, nightly, 1.66.0]
6060
target:
6161
[
6262
x86_64-unknown-linux-gnu,

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
9+
### Fixed
10+
- Fix the alignment of the collector and validate function (#255)
11+
12+
### Changed
13+
- Bump the MSRV to 1.66.0 (#255)
14+
715
## [0.13.0] - 2023-09-27
816

917
### Changed

Cargo.lock

+57-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ description = "An internal perf tools for rust programs."
88
repository = "https://github.com/tikv/pprof-rs"
99
documentation = "https://docs.rs/pprof/"
1010
readme = "README.md"
11-
rust-version = "1.64.0" # MSRV
11+
rust-version = "1.66.0" # MSRV
1212

1313
[features]
1414
default = ["cpp"]
@@ -39,6 +39,7 @@ prost = { version = "0.12", optional = true }
3939
prost-derive = { version = "0.12", optional = true }
4040
protobuf = { version = "2.0", optional = true }
4141
criterion = {version = "0.5", optional = true}
42+
aligned-vec = "0.6"
4243

4344
[dependencies.symbolic-demangle]
4445
version = "12.1"

src/addr_validate.rs

+6
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ fn open_pipe() -> nix::Result<()> {
6969
// `write()` will return an error the error number should be `EFAULT` in most
7070
// cases, but we regard all errors (except EINTR) as a failure of validation
7171
pub fn validate(addr: *const libc::c_void) -> bool {
72+
// it's a short circuit for null pointer, as it'll give an error in
73+
// `std::slice::from_raw_parts` if the pointer is null.
74+
if addr.is_null() {
75+
return false;
76+
}
77+
7278
const CHECK_LENGTH: usize = 2 * size_of::<*const libc::c_void>() / size_of::<u8>();
7379

7480
// read data in the pipe

src/collector.rs

+68-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::io::{Read, Seek, SeekFrom, Write};
88

99
use crate::frames::UnresolvedFrames;
1010

11+
use aligned_vec::AVec;
1112
use tempfile::NamedTempFile;
1213

1314
pub const BUCKETS: usize = 1 << 12;
@@ -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(())
@@ -192,10 +196,16 @@ impl<T> TempFdArray<T> {
192196
}
193197

194198
fn try_iter(&self) -> std::io::Result<impl Iterator<Item = &T>> {
195-
let mut file_vec = Vec::new();
199+
let size = BUFFER_LENGTH * self.flush_n * std::mem::size_of::<T>();
200+
201+
let mut file_vec = AVec::with_capacity(std::mem::align_of::<T>(), size);
196202
let mut file = self.file.reopen()?;
197-
file.seek(SeekFrom::Start(0))?;
198-
file.read_to_end(&mut file_vec)?;
203+
204+
unsafe {
205+
// it's safe as the capacity is initialized to `size`, and it'll be filled with `size` bytes
206+
file_vec.set_len(size);
207+
}
208+
file.read_exact(&mut file_vec[0..size])?;
199209
file.seek(SeekFrom::End(0))?;
200210

201211
Ok(TempFdArrayIterator {
@@ -208,7 +218,7 @@ impl<T> TempFdArray<T> {
208218

209219
pub struct TempFdArrayIterator<'a, T> {
210220
pub buffer: &'a [T],
211-
pub file_vec: Vec<u8>,
221+
pub file_vec: AVec<u8>,
212222
pub index: usize,
213223
}
214224

@@ -266,7 +276,7 @@ mod test_utils {
266276
use super::*;
267277
use std::collections::BTreeMap;
268278

269-
pub fn add_map(hashmap: &mut BTreeMap<usize, isize>, entry: &Entry<usize>) {
279+
pub fn add_map<T: std::cmp::Ord + Copy>(hashmap: &mut BTreeMap<T, isize>, entry: &Entry<T>) {
270280
match hashmap.get_mut(&entry.item) {
271281
None => {
272282
hashmap.insert(entry.item, entry.count);
@@ -359,4 +369,57 @@ mod tests {
359369
}
360370
}
361371
}
372+
373+
#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Default, Clone, Copy)]
374+
struct AlignTest {
375+
a: u16,
376+
b: u32,
377+
c: u64,
378+
d: u64,
379+
}
380+
381+
// collector_align_test uses a bigger item to test the alignment of the collector
382+
#[test]
383+
fn collector_align_test() {
384+
let mut collector = Collector::new().unwrap();
385+
let mut real_map = BTreeMap::new();
386+
387+
for item in 0..(1 << 12) * 4 {
388+
for _ in 0..(item % 4) {
389+
collector
390+
.add(
391+
AlignTest {
392+
a: item as u16,
393+
b: item as u32,
394+
c: item as u64,
395+
d: item as u64,
396+
},
397+
1,
398+
)
399+
.unwrap();
400+
}
401+
}
402+
403+
collector.try_iter().unwrap().for_each(|entry| {
404+
test_utils::add_map(&mut real_map, entry);
405+
});
406+
407+
for item in 0..(1 << 12) * 4 {
408+
let count = (item % 4) as isize;
409+
let align_item = AlignTest {
410+
a: item as u16,
411+
b: item as u32,
412+
c: item as u64,
413+
d: item as u64,
414+
};
415+
match real_map.get(&align_item) {
416+
Some(value) => {
417+
assert_eq!(count, *value);
418+
}
419+
None => {
420+
assert_eq!(count, 0);
421+
}
422+
}
423+
}
424+
}
362425
}

src/profiler.rs

+1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ impl Drop for ErrnoProtector {
281281
))),
282282
allow(unused_variables)
283283
)]
284+
#[allow(clippy::unnecessary_cast)]
284285
extern "C" fn perf_signal_handler(
285286
_signal: c_int,
286287
_siginfo: *mut libc::siginfo_t,

0 commit comments

Comments
 (0)