Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing for windows #122

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ protobuf-codec = ["protobuf", "protobuf-codegen-pure", "_protobuf"]
cpp = ["symbolic-demangle/cpp"]

[dependencies]
backtrace = "0.3"
backtrace = { git = "https://github.com/Jardynq/backtrace-rs" }
once_cell = "1.9"
libc = "^0.2.66"
log = "0.4"
Expand All @@ -37,6 +37,15 @@ prost-derive = { version = "0.10", optional = true }
protobuf = { version = "2.0", optional = true }
criterion = {version = "0.3", optional = true}

[target.'cfg(windows)'.dependencies]
winproc = "0.6.4"
winapi = {version = "0.3", features = [
"processthreadsapi",
"winnt",
"errhandlingapi",
"winuser"
] }

[dependencies.symbolic-demangle]
version = "8.0"
default-features = false
Expand Down
4 changes: 2 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("{0}")]
NixError(#[from] nix::Error),
//#[error("{0}")]
//OsError(#[from] nix::Error),
#[error("{0}")]
IoError(#[from] std::io::Error),
#[error("create profiler error")]
Expand Down
146 changes: 30 additions & 116 deletions src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::convert::TryInto;
use std::os::raw::c_int;

use backtrace::Frame;
use nix::sys::signal;
//use nix::sys::signal;
use once_cell::sync::Lazy;
use parking_lot::RwLock;
use smallvec::SmallVec;
Expand Down Expand Up @@ -156,117 +156,41 @@ impl<'a> Drop for ProfilerGuard<'a> {
}
}

fn write_thread_name_fallback(current_thread: libc::pthread_t, name: &mut [libc::c_char]) {
let mut len = 0;
let mut base = 1;

while current_thread as u128 > base && len < MAX_THREAD_NAME {
base *= 10;
len += 1;
}

let mut index = 0;
while index < len && base > 1 {
base /= 10;

name[index] = match (48 + (current_thread as u128 / base) % 10).try_into() {
Ok(digit) => digit,
Err(_) => {
log::error!("fail to convert thread_id to string");
0
}
};

index += 1;
}
}

#[cfg(not(all(any(target_os = "linux", target_os = "macos"), target_env = "gnu")))]
fn write_thread_name(current_thread: libc::pthread_t, name: &mut [libc::c_char]) {
write_thread_name_fallback(current_thread, name);
}

#[cfg(all(any(target_os = "linux", target_os = "macos"), target_env = "gnu"))]
fn write_thread_name(current_thread: libc::pthread_t, name: &mut [libc::c_char]) {
let name_ptr = name as *mut [libc::c_char] as *mut libc::c_char;
let ret = unsafe { libc::pthread_getname_np(current_thread, name_ptr, MAX_THREAD_NAME) };

if ret != 0 {
write_thread_name_fallback(current_thread, name);
}
}
fn perf_worker_thread() {
let worker_id = unsafe { winapi::um::processthreadsapi::GetCurrentThreadId() };
loop {
let proc = winproc::Process::current();
let threads = proc.thread_ids().unwrap();

#[no_mangle]
#[cfg_attr(
not(all(any(target_arch = "x86_64", target_arch = "aarch64"))),
allow(unused_variables)
)]
extern "C" fn perf_signal_handler(
_signal: c_int,
_siginfo: *mut libc::siginfo_t,
ucontext: *mut libc::c_void,
) {
if let Some(mut guard) = PROFILER.try_write() {
if let Ok(profiler) = guard.as_mut() {
#[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64")))]
if !ucontext.is_null() {
let ucontext: *mut libc::ucontext_t = ucontext as *mut libc::ucontext_t;

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
let addr =
unsafe { (*ucontext).uc_mcontext.gregs[libc::REG_RIP as usize] as usize };

#[cfg(all(target_arch = "x86_64", target_os = "macos"))]
let addr = unsafe {
let mcontext = (*ucontext).uc_mcontext;
if mcontext.is_null() {
0
} else {
(*mcontext).__ss.__rip as usize
if let Some(mut guard) = PROFILER.try_write() {
if let Ok(profiler) = guard.as_mut() {
for id in threads {
if id == worker_id {
continue;
}
};

#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
let addr = unsafe { (*ucontext).uc_mcontext.pc as usize };

#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
let addr = unsafe {
let mcontext = (*ucontext).uc_mcontext;
if mcontext.is_null() {
0
} else {
(*mcontext).__ss.__pc as usize
let mut bt: SmallVec<[Frame; MAX_DEPTH]> = SmallVec::with_capacity(MAX_DEPTH);
let mut index = 0;

unsafe {
const ALL_ACCESS: u32 = 2_097_151u32;
let handle = winapi::um::processthreadsapi::OpenThread(ALL_ACCESS, 0, id) as usize;

backtrace::trace_thread_unsynchronized(handle as _, |frame| {
if index < MAX_DEPTH {
bt.push(frame.clone());
index += 1;
true
} else {
false
}
});
}
};

if profiler.is_blocklisted(addr) {
return;

profiler.sample(bt, format!("{:x}", id).as_bytes(), id as u64);
}
}

let mut bt: SmallVec<[Frame; MAX_DEPTH]> = SmallVec::with_capacity(MAX_DEPTH);
let mut index = 0;

unsafe {
backtrace::trace_unsynchronized(|frame| {
if index < MAX_DEPTH {
bt.push(frame.clone());
index += 1;
true
} else {
false
}
});
}

let current_thread = unsafe { libc::pthread_self() };
let mut name = [0; MAX_THREAD_NAME];
let name_ptr = &mut name as *mut [libc::c_char] as *mut libc::c_char;

write_thread_name(current_thread, &mut name);

let name = unsafe { std::ffi::CStr::from_ptr(name_ptr) };
profiler.sample(bt, name.to_bytes(), current_thread as u64);
}
}
}
Expand Down Expand Up @@ -328,21 +252,11 @@ impl Profiler {
}

fn register_signal_handler(&self) -> Result<()> {
let handler = signal::SigHandler::SigAction(perf_signal_handler);
let sigaction = signal::SigAction::new(
handler,
signal::SaFlags::SA_SIGINFO,
signal::SigSet::empty(),
);
unsafe { signal::sigaction(signal::SIGPROF, &sigaction) }?;

std::thread::spawn(perf_worker_thread);
Ok(())
}

fn unregister_signal_handler(&self) -> Result<()> {
let handler = signal::SigHandler::SigIgn;
unsafe { signal::signal(signal::SIGPROF, handler) }?;

Ok(())
}

Expand Down
22 changes: 3 additions & 19 deletions src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ struct Itimerval {
pub it_value: Timeval,
}

extern "C" {
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
}


const ITIMER_PROF: c_int = 2;

Expand All @@ -40,14 +38,7 @@ impl Timer {
let it_value = it_interval.clone();

unsafe {
setitimer(
ITIMER_PROF,
&mut Itimerval {
it_interval,
it_value,
},
null_mut(),
)

};

Timer {
Expand Down Expand Up @@ -76,14 +67,7 @@ impl Drop for Timer {
};
let it_value = it_interval.clone();
unsafe {
setitimer(
ITIMER_PROF,
&mut Itimerval {
it_interval,
it_value,
},
null_mut(),
)

};
}
}
Expand Down