-
Notifications
You must be signed in to change notification settings - Fork 401
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
There were two main error cases remaining when I test on linux: 1) Failed to get a native stack I've seen cases where we can only get 1-2 native frames, even though there is a valid python stack being returned. This seems to be in libmkl_avx512.so on anaconda 3.7.2 - and I failed to unwind with libunwind/gdb and the gimli based unwinder. GDB in this case returned a message complaining about a 'corrupt stack trace'. Rather than error out, just insert the native frames w/ the python stack. 2) 1 more native python frame The other error seems to be where we have exactly 1 more python PyEval_Frame* function in the native stack than we have frames for in the python stack. This seems to happen when the python function is finished, and the frame structure has been updated in python but the native function hasn't exitted yet. Just allow this for now. Also add an example program to stress test native unwinding.
- Loading branch information
Showing
4 changed files
with
96 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// This example loops over native stack traces until it fails to get one for any reason | ||
extern crate remoteprocess; | ||
extern crate env_logger; | ||
#[macro_use] | ||
extern crate log; | ||
extern crate failure; | ||
extern crate py_spy; | ||
|
||
fn native_stress_test(pid: remoteprocess::Pid) -> Result<(), failure::Error> { | ||
|
||
let config = py_spy::Config{native: true, ..Default::default() }; | ||
let mut spy = py_spy::PythonSpy::retry_new(pid, &config, 3)?; | ||
|
||
|
||
let mut success = 0; | ||
let mut failed = 0; | ||
loop { | ||
match spy.get_stack_traces() { | ||
Ok(_) => { | ||
success += 1; | ||
if success % 1000 == 0 { | ||
info!("Success {} fail {}", success, failed) | ||
} | ||
}, | ||
Err(e) => { | ||
error!("Failed to get stack traces: {:#?}", e); | ||
for (_i, suberror) in e.iter_chain().enumerate() { | ||
eprintln!("Reason: {:?}", suberror); | ||
} | ||
|
||
failed += 1; | ||
info!("Success {} fail {}", success, failed); | ||
} | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
|
||
#[cfg(unwind)] | ||
fn main() { | ||
env_logger::init(); | ||
|
||
let args: Vec<String> = std::env::args().collect(); | ||
|
||
let pid = if args.len() > 1 { | ||
args[1].parse::<remoteprocess::Pid>().expect("invalid pid") | ||
} else { | ||
error!("must specify a pid!"); | ||
return; | ||
}; | ||
|
||
if let Err(e) = native_stress_test(pid) { | ||
println!("Failed to get backtrace {:?}", e); | ||
} | ||
} | ||
|
||
#[cfg(not(unwind))] | ||
fn main() { | ||
panic!("unwind not supported!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters