-
Notifications
You must be signed in to change notification settings - Fork 108
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
Unwind through frame pointer #116
Conversation
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
7c8d32f
to
1f5d3fc
Compare
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
If the Rust std library or other C/C++ dependencies are not compiled with frame pointers, what will the result look like? Will it panic or just drop some information? |
@sticnarf panic. As I cannot give a proper upper bound of the stack 😢 . (And that's exactly how I found those problem) I remember @mornyx was working on getting a stack boundary, but I don't know the progress. And I still have some confusion about how @mornyx will implement the boundary check, as the stack for non-main thread is allocated dynamically. |
I use https://github.com/mornyx/unwind/blob/master/src/utils/maps.rs (I just judge whether the address is readable or not, without distinguishing the stack address or instruction address.) The only thing that needs to be confirmed is whether the address range of each thread will change once it is allocated? If so, I think we should remove |
@mornyx It will, but I think it doesn't matter (at least for unwinding). Because though there will be new maps created through |
When I write the following test in Rust: #[test]
fn test_address_is_readable() {
let v = 0;
assert!(address_is_readable(&v as *const i32 as u64));
} I found that the address of the variable |
@mornyx Sure. The As the
We can assume that, 1 is the subset of the intersection of 2 and 3. (This is only about the glibc implementation of |
@mornyx Oops, there is still a problem: the 2 and 3 doesn't have other meaningful relationship, which means the accessible memory in 2 is not necessarily accessible in 3 (because the mmap can be unmapped). It's still not 100% safe to only read once for every thread. |
As you said, the space for the thread stack is allocated by glibc and passed to |
@mornyx The "2" contains not only the "stack", it also contains all heaps, mmapped files, etc. The mallocator will Take the frame pointer for an example. Consider the situation: the program (which omit the frame pointer) use We can shrink the possibility by ignoring any mmap backed by a file, but the mallocator is still possible to call |
@YangKeao Thanks for the detailed explanation! I think we do need to parse each time. I'm going to measure the performance overhead and decide if we need a better idea.. |
I've done sysbench tests on my local cluster of VMs, but have not observed a noticeable performance regression (PS. with |
In general, after opening framer-pointer (with branch My test environment is as follows:
|
src/lib.rs
Outdated
#[cfg(target_os = "linux")] | ||
mod addr_validate; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should also provide addr_validate
for macOS, this is possible. The only problem is that macOS doesn't have pipe2
, but we can simply simulate it.
Here is a possible piece of code:
#[inline]
#[cfg(target_os = "linux")]
unsafe fn create_pipe(fds: *mut libc::c_int) -> libc::c_int {
libc::pipe2(fds, libc::O_CLOEXEC | libc::O_NONBLOCK)
}
#[cfg(target_os = "macos")]
unsafe fn create_pipe(fds: *mut libc::c_int) -> libc::c_int {
let res = libc::pipe(fds);
if res != 0 {
return res;
}
let fds = fds as *mut [libc::c_int; 2];
for n in 0..2 {
let mut flags = libc::fcntl((*fds)[n], libc::F_GETFD);
flags |= libc::O_CLOEXEC;
let res = libc::fcntl((*fds)[n], libc::F_SETFD, flags);
if res != 0 {
return res;
}
let mut flags = libc::fcntl((*fds)[n], libc::F_GETFL);
flags |= libc::O_NONBLOCK;
let res = libc::fcntl((*fds)[n], libc::F_SETFL, flags);
if res != 0 {
return res;
}
}
0
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I rework an implementation with nix
. Could you test it on Mac OS (as I don't have a mac environment)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran cargo test --features=flamegraph
on ARM64 macOS and got test addr_validate::test::failed_validate has been running for over 60 seconds
. I guess the problem happens because we haven't set O_NONBLOCK
for pipe on macOS at src/addr_validate.rs#L21-L38.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mornyx PTAL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FdFlag::O_NONBLOCK
does not exist, I have made a suggestion below.
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
96caf30
to
1136ee1
Compare
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
Signed-off-by: YangKeao <[email protected]>
LGTM |
} | ||
|
||
#[inline] | ||
#[cfg(target_os = "macos")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, addr validation is only enabled on Linux. But there is an implementation for macos?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. It's a mistake. I'll remove the conditional flag on addr validate.
Signed-off-by: YangKeao <[email protected]>
Add the feature to unwind through frame pointer in
pprof-rs
.The frame pointer has much better performance and stability. The only problem is that we cannot ensure every components have correct frame pointer. During my testing, I have met several problems:
cargo
to rebuild the std library from source can solve this.libstdc++
in my PC doesn't enable the frame pointer (but I used gentoo, so I could recompile it simply)Compiling with
CFLAGS="-fno-omit-frame-pointer", CXXFLAGS="-fno-omit-frame-pointer" RUSTFLAGS="-Cforce-frame-pointers=yes" cargo +nightly build -Z build-std
will get a correct behavior.