Skip to content

Commit c855009

Browse files
committed
Moved platform impl into traits
+ moved write_thread_name_fallback into profiler, since it's platform agnostic Signed-off-by: Christian Jordan <[email protected]>
1 parent c12b87a commit c855009

13 files changed

+210
-215
lines changed

src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ mod error;
5353
mod frames;
5454
mod profiler;
5555
mod report;
56+
mod timer;
57+
mod validator;
5658

5759
pub use self::collector::{Collector, HashCounter};
5860
pub use self::error::{Error, Result};
5961
pub use self::frames::{Frames, Symbol};
60-
pub use self::platform::addr_validate::validate;
6162
pub use self::profiler::{ProfilerGuard, ProfilerGuardBuilder};
6263
pub use self::report::{Report, ReportBuilder, UnresolvedReport};
64+
pub use self::validator::addr_validate;
6365

6466
#[cfg(feature = "flamegraph")]
6567
pub use inferno::flamegraph;

src/platform/mod.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#[cfg(any(target_os = "linux", target_os = "macos"))]
22
mod nix_impl {
3-
pub mod addr_validate;
4-
pub mod profiler;
5-
pub mod timer;
3+
mod addr_validate;
4+
mod profiler;
5+
mod timer;
66

77
#[cfg(all(
88
any(target_arch = "x86_64", target_arch = "aarch64"),
@@ -30,9 +30,9 @@ mod nix_impl {
3030

3131
#[cfg(target_os = "windows")]
3232
mod windows_impl {
33-
pub mod addr_validate;
34-
pub mod profiler;
35-
pub mod timer;
33+
mod addr_validate;
34+
mod profiler;
35+
mod timer;
3636

3737
#[cfg(feature = "frame-pointer")]
3838
std::compile_error!("frame-pointer feature is currently not supported on windows.");

src/platform/nix_impl/addr_validate.rs

+45-41
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,50 @@ use nix::{
55
unistd::{close, read, write},
66
};
77

8+
use crate::validator::{Validator, ValidatorImpl};
9+
810
thread_local! {
911
static MEM_VALIDATE_PIPE: RefCell<[i32; 2]> = RefCell::new([-1, -1]);
1012
}
1113

14+
impl ValidatorImpl for Validator {
15+
fn addr_validate(addr: *const libc::c_void) -> bool {
16+
const CHECK_LENGTH: usize = 2 * size_of::<*const libc::c_void>() / size_of::<u8>();
17+
18+
// read data in the pipe
19+
let valid_read = MEM_VALIDATE_PIPE.with(|pipes| {
20+
let pipes = pipes.borrow();
21+
loop {
22+
let mut buf = [0u8; CHECK_LENGTH];
23+
24+
match read(pipes[0], &mut buf) {
25+
Ok(bytes) => break bytes > 0,
26+
Err(_err @ Errno::EINTR) => continue,
27+
Err(_err @ Errno::EAGAIN) => break true,
28+
Err(_) => break false,
29+
}
30+
}
31+
});
32+
33+
if !valid_read && open_pipe().is_err() {
34+
return false;
35+
}
36+
37+
MEM_VALIDATE_PIPE.with(|pipes| {
38+
let pipes = pipes.borrow();
39+
loop {
40+
let buf = unsafe { std::slice::from_raw_parts(addr as *const u8, CHECK_LENGTH) };
41+
42+
match write(pipes[1], buf) {
43+
Ok(bytes) => break bytes > 0,
44+
Err(_err @ Errno::EINTR) => continue,
45+
Err(_) => break false,
46+
}
47+
}
48+
})
49+
}
50+
}
51+
1252
#[inline]
1353
#[cfg(target_os = "linux")]
1454
fn create_pipe() -> nix::Result<(i32, i32)> {
@@ -58,65 +98,29 @@ fn open_pipe() -> nix::Result<()> {
5898
})
5999
}
60100

61-
pub fn validate(addr: *const libc::c_void) -> bool {
62-
const CHECK_LENGTH: usize = 2 * size_of::<*const libc::c_void>() / size_of::<u8>();
63-
64-
// read data in the pipe
65-
let valid_read = MEM_VALIDATE_PIPE.with(|pipes| {
66-
let pipes = pipes.borrow();
67-
loop {
68-
let mut buf = [0u8; CHECK_LENGTH];
69-
70-
match read(pipes[0], &mut buf) {
71-
Ok(bytes) => break bytes > 0,
72-
Err(_err @ Errno::EINTR) => continue,
73-
Err(_err @ Errno::EAGAIN) => break true,
74-
Err(_) => break false,
75-
}
76-
}
77-
});
78-
79-
if !valid_read && open_pipe().is_err() {
80-
return false;
81-
}
82-
83-
MEM_VALIDATE_PIPE.with(|pipes| {
84-
let pipes = pipes.borrow();
85-
loop {
86-
let buf = unsafe { std::slice::from_raw_parts(addr as *const u8, CHECK_LENGTH) };
87-
88-
match write(pipes[1], buf) {
89-
Ok(bytes) => break bytes > 0,
90-
Err(_err @ Errno::EINTR) => continue,
91-
Err(_) => break false,
92-
}
93-
}
94-
})
95-
}
96-
97101
#[cfg(test)]
98102
mod test {
99-
use super::*;
103+
use crate::addr_validate;
100104

101105
#[test]
102106
fn validate_stack() {
103107
let i = 0;
104108

105-
assert!(validate(&i as *const _ as *const libc::c_void));
109+
assert!(addr_validate(&i as *const _ as *const libc::c_void));
106110
}
107111

108112
#[test]
109113
fn validate_heap() {
110114
let vec = vec![0; 1000];
111115

112116
for i in vec.iter() {
113-
assert!(validate(i as *const _ as *const libc::c_void));
117+
assert!(addr_validate(i as *const _ as *const libc::c_void));
114118
}
115119
}
116120

117121
#[test]
118122
fn failed_validate() {
119-
assert!(!validate(std::ptr::null::<libc::c_void>()));
120-
assert!(!validate(-1_i32 as usize as *const libc::c_void))
123+
assert!(!addr_validate(std::ptr::null::<libc::c_void>()));
124+
assert!(!addr_validate(-1_i32 as usize as *const libc::c_void))
121125
}
122126
}

src/platform/nix_impl/frame_pointer.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::ptr::null_mut;
44

55
use libc::c_void;
66

7-
use crate::validate;
7+
use crate::addr_validate;
88

99
#[derive(Clone, Debug)]
1010
pub struct Frame {
@@ -91,7 +91,7 @@ impl crate::backtrace::Trace for Trace {
9191
break;
9292
}
9393

94-
if !validate(frame_pointer as *const libc::c_void) {
94+
if !addr_validate(frame_pointer as *const libc::c_void) {
9595
break;
9696
}
9797
last_frame_pointer = frame_pointer;

src/platform/nix_impl/profiler.rs

+18-41
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,38 @@
11
use std::os::raw::c_int;
22
use std::time::SystemTime;
33

4-
use crate::backtrace::{Frame, Trace, TraceImpl};
54
use smallvec::SmallVec;
65

76
use nix::sys::signal;
87

8+
use crate::backtrace::{Frame, Trace, TraceImpl};
99
use crate::error::Result;
10-
use crate::profiler::PROFILER;
10+
use crate::profiler::{write_thread_name_fallback, Profiler, ProfilerImpl, PROFILER};
1111
use crate::{MAX_DEPTH, MAX_THREAD_NAME};
1212

13-
pub fn register() -> Result<()> {
14-
let handler = signal::SigHandler::SigAction(perf_signal_handler);
15-
let sigaction = signal::SigAction::new(
16-
handler,
17-
signal::SaFlags::SA_SIGINFO,
18-
signal::SigSet::empty(),
19-
);
20-
unsafe { signal::sigaction(signal::SIGPROF, &sigaction) }?;
21-
22-
Ok(())
23-
}
24-
pub fn unregister() -> Result<()> {
25-
let handler = signal::SigHandler::SigIgn;
26-
unsafe { signal::signal(signal::SIGPROF, handler) }?;
27-
28-
Ok(())
29-
}
30-
31-
fn write_thread_name_fallback(current_thread: libc::pthread_t, name: &mut [libc::c_char]) {
32-
let mut len = 0;
33-
let mut base = 1;
34-
35-
while current_thread as u128 > base && len < MAX_THREAD_NAME {
36-
base *= 10;
37-
len += 1;
13+
impl ProfilerImpl for Profiler {
14+
fn register(&mut self) -> Result<()> {
15+
let handler = signal::SigHandler::SigAction(perf_signal_handler);
16+
let sigaction = signal::SigAction::new(
17+
handler,
18+
signal::SaFlags::SA_SIGINFO,
19+
signal::SigSet::empty(),
20+
);
21+
unsafe { signal::sigaction(signal::SIGPROF, &sigaction) }?;
22+
23+
Ok(())
3824
}
25+
fn unregister(&mut self) -> Result<()> {
26+
let handler = signal::SigHandler::SigIgn;
27+
unsafe { signal::signal(signal::SIGPROF, handler) }?;
3928

40-
let mut index = 0;
41-
while index < len && base > 1 {
42-
base /= 10;
43-
44-
name[index] = match (48 + (current_thread as u128 / base) % 10).try_into() {
45-
Ok(digit) => digit,
46-
Err(_) => {
47-
log::error!("fail to convert thread_id to string");
48-
0
49-
}
50-
};
51-
52-
index += 1;
29+
Ok(())
5330
}
5431
}
5532

5633
#[cfg(not(all(any(target_os = "linux", target_os = "macos"), target_env = "gnu")))]
5734
fn write_thread_name(current_thread: libc::pthread_t, name: &mut [libc::c_char]) {
58-
write_thread_name_fallback(current_thread, name);
35+
crate::profiler::write_thread_name_fallback(current_thread, name);
5936
}
6037

6138
#[cfg(all(any(target_os = "linux", target_os = "macos"), target_env = "gnu"))]

src/platform/nix_impl/timer.rs

+12-58
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,32 @@
11
// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
22

3+
use crate::timer::{Timer, TimerImpl};
4+
35
use std::os::raw::c_int;
46
use std::ptr::null_mut;
5-
use std::time::{Duration, Instant, SystemTime};
7+
8+
extern "C" {
9+
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
10+
}
11+
12+
const ITIMER_PROF: c_int = 2;
613

714
#[repr(C)]
815
#[derive(Clone)]
916
struct Timeval {
1017
pub tv_sec: i64,
1118
pub tv_usec: i64,
1219
}
13-
1420
#[repr(C)]
1521
#[derive(Clone)]
1622
struct Itimerval {
1723
pub it_interval: Timeval,
1824
pub it_value: Timeval,
1925
}
2026

21-
extern "C" {
22-
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
23-
}
24-
25-
const ITIMER_PROF: c_int = 2;
26-
27-
pub struct Timer {
28-
pub frequency: c_int,
29-
pub start_time: SystemTime,
30-
pub start_instant: Instant,
31-
}
32-
33-
impl Timer {
34-
pub fn new(frequency: c_int) -> Timer {
35-
let interval = 1e6 as i64 / i64::from(frequency);
27+
impl TimerImpl for Timer {
28+
fn start(&mut self) {
29+
let interval = 1e6 as i64 / i64::from(self.frequency);
3630
let it_interval = Timeval {
3731
tv_sec: interval / 1e6 as i64,
3832
tv_usec: interval % 1e6 as i64,
@@ -49,27 +43,8 @@ impl Timer {
4943
null_mut(),
5044
)
5145
};
52-
53-
Timer {
54-
frequency,
55-
start_time: SystemTime::now(),
56-
start_instant: Instant::now(),
57-
}
5846
}
59-
60-
/// Returns a `ReportTiming` struct having this timer's frequency and start
61-
/// time; and the time elapsed since its creation as duration.
62-
pub fn timing(&self) -> ReportTiming {
63-
ReportTiming {
64-
frequency: self.frequency,
65-
start_time: self.start_time,
66-
duration: self.start_instant.elapsed(),
67-
}
68-
}
69-
}
70-
71-
impl Drop for Timer {
72-
fn drop(&mut self) {
47+
fn stop(&mut self) {
7348
let it_interval = Timeval {
7449
tv_sec: 0,
7550
tv_usec: 0,
@@ -87,24 +62,3 @@ impl Drop for Timer {
8762
};
8863
}
8964
}
90-
91-
/// Timing metadata for a collected report.
92-
#[derive(Clone)]
93-
pub struct ReportTiming {
94-
/// Frequency at which samples were collected.
95-
pub frequency: i32,
96-
/// Collection start time.
97-
pub start_time: SystemTime,
98-
/// Collection duration.
99-
pub duration: Duration,
100-
}
101-
102-
impl Default for ReportTiming {
103-
fn default() -> Self {
104-
Self {
105-
frequency: 1,
106-
start_time: SystemTime::UNIX_EPOCH,
107-
duration: Default::default(),
108-
}
109-
}
110-
}
+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
pub fn validate() -> bool {
2-
unimplemented!()
1+
use crate::validator::{Validator, ValidatorImpl};
2+
3+
impl ValidatorImpl for Validator {
4+
fn addr_validate(_: *const libc::c_void) -> bool {
5+
unimplemented!()
6+
}
37
}

src/platform/windows_impl/profiler.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use crate::error::Result;
2+
use crate::profiler::{Profiler, ProfilerImpl};
23

3-
pub fn register() -> Result<()> {
4-
Ok(())
5-
}
6-
pub fn unregister() -> Result<()> {
7-
Ok(())
4+
impl ProfilerImpl for Profiler {
5+
fn register(&mut self) -> Result<()> {
6+
unimplemented!()
7+
}
8+
fn unregister(&mut self) -> Result<()> {
9+
unimplemented!()
10+
}
811
}

0 commit comments

Comments
 (0)