-
Notifications
You must be signed in to change notification settings - Fork 4
Conversation
src/libcore/yk_swt.rs
Outdated
/// but we can do neither due to libcore restrictions. | ||
buf: *mut MirLoc, | ||
/// The number of items in the above array. | ||
len: u32, |
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.
This should be usize
I think?
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.
Sure. The only downside would be that it wouldn't fit in a register on 32-bit. Does it bother us?
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.
On a 32-bit machine, usize
will be 32 bits.
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.
Duh! Yep. Brainfart :P
src/libcore/yk_swt.rs
Outdated
self.len | ||
} | ||
|
||
/// Return a pointer to the raw trace buffer. Provided so that the consumer can free it. |
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.
"Can" is a very vague word. Are they required to free it? If so, this should probably be fn buf(self) -> ...
. If not... this seems very dangerous!
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.
Good point.
If you agree with the abstraction discussion point above this becomes moot, but I'm happy to implement your suggestion in the interim.
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 haven't fully understood how the abstraction discussion will solve this, but if all we have to do is turn &self
into self
, we might as well do it in this PR.
src/libcore/yk_swt.rs
Outdated
} | ||
|
||
/// Returns the location at index `idx` or `None` if the index is out of bounds. | ||
pub fn loc<'a>(&'a self, idx: u32) -> Option<&'a MirLoc> { |
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 suggest we make this panic if idx
is out of bounds and return MirLoc
directly rather than through an Option
. It makes things quite a bit faster and given we'll be using this a lot, it's worth it.
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.
OK
src/libcore/yk_swt_impl.c
Outdated
if (tl_trace_cap >= UINT32_MAX / 2) { | ||
errx(EXIT_FAILURE, "%s: trace capacity would overflow", __func__); | ||
} | ||
size_t new_cap = tl_trace_cap * 2; |
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.
This is a bit dangerous, I think: it means we're logarithmically increasing the buffer size. In other words, the bigger the buffer is, the more likely that we end up wasting lots of memory. We probably want some sort of threshold here that says something like "if the buffer is bigger than XMiB, then only add 1MiB extra storage" or similar.
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.
it means we're logarithmically increasing
exponentially, yeah.
How about we grow linearly for now? We can be clever later.
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.
Exponentially, oops!
I'm happy to simplify and be cleverer later.
|
||
pub fn main() { | ||
start_tracing(); | ||
let _ = work(); |
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.
Why the let _ =
?
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 was trying to encourage the compiler to not remove the call altogether.
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'm about 98% certain that assigning to the dummy variable won't affect what the compiler does in that way. You might want the black_box
function?
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.
OK, I'll look into that.
|
||
for idx in 0..len { | ||
let loc = trace.loc(idx).unwrap(); | ||
assert_ne!(loc.crate_hash, 0); // A crate hash is so unlikely to be zero. |
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.
"So unlikely"?!
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.
In the same way a hash collision is unlikely to cause a problem in git.
Is it the wording that bothers you, or the assertion itself?
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.
The wording, definitely bothers me ;) Given that the assertion is incorrect in some cases, I'm also unsure if it's a wise thing to be asserting.
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.
OK, let's kill the assert.
By the way, this code is not immune from the signal handling issue we discussed the other day. It's not yet clear to me whether clever use of atomic bools could detect if we have re-entered the trace recorder a second time and do something (panic or invalidate the trace). Perhaps we can think about that later. |
If we have a thread-local atomic (I know that sounds like a contradiction!) bool, we can set it when we start tracing and unset it when we're done. If someone tries to set it when it's set... boom! |
Yeah, that's what I was thinking. We might even get away with relaxed ordering. |
I'm thinking of promoting |
A relaxed bool is definitely fine for this use case. I thought the idea would basically be to make |
Actually I was unable to convince myself that relaxed is OK. I think we need acquire and release to ensure that the body of the function remains between the enclosing set/clear of the flag.
I don't think that's sufficient for our case.
The problem is, any value of |
That's irrelevant. We simply need to see if the bool is set to know if tracing is occurring. Other side-effects in the program are of no use.
What does "any value ... is valid" mean? |
I don't think that's right. The trace recorder basically does this:
If we use relaxed orderings, the compiler could happily emit:
Suppose we were interrupted at
I wonder if I should post my code, as it probably communicates it better than I can explain in prose. |
You're right: we need to do it as a lock. So we need to use acquire/release ordering for the set/unset of the bool respectively. |
Well, it's not a lock per-se, but in order to reliably decide if we have re-entered, the flag must be true for the entire duration of the function, i.e. with the full function body between the flag set and clear. I've also managed to convince myself that the checks in start/stop_tracing will still work without atomics, even in the presence of signal handlers. The last commit should address all of the outstanding comments. I also forgot to add some test files, and included them in this commit. I did full tests at the time of raising the PR, but not since our modifications, so it may explode yet :) Ready for re-review. |
I still don't understand why we have |
I don't see how, but I may be wrong. Which one do you think can be removed? |
What is the difference between the two? They both say "I'm tracing" I think? |
I think we both agree that |
If tl_tracing_en is false, then tl_entered_recorder must be false too I think? |
Afraid not. Each block calls the trace recorder regardless of if the thread is currently tracing. Inside the tracing impl, the recorder then bails out early if the thread is not tracing:
|
OK, I think I'm with you now. I'm wondering if we can find better names for these? I'm not sure the |
Fine by me. The only reason I added the prefix was to make it clear it's thread local, but maybe it isn't as useful as first thought. |
OK, shall we try them on for size? |
I'm just applying those, and wondering if |
|
That should address your outstanding comments. |
Please squash. |
src/libcore/yk_swt_impl.c
Outdated
// On success the trace buffer is returned and the number of locations it | ||
// holds is written to `*ret_trace_len`. It is the responsibility of the caller | ||
// to free the trace buffer. A NULL pointer is returned on error (if tracing | ||
// wasn't started, or the trace was invalidated). |
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.
Maybe add "Calling this function without having previously called yk_swt_start_tracing_impl will lead to undefined behaviour."?
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.
Not true. I've designed it in such a way that it would return NULL reliably.
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.
Even if it's currently safe, the "undefined behaviour" sentence is a big red flag to callers that says "you actually have to do this!", plus it gives us a get-out-of-jail-free card in the future if we need to change things.
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.
you actually have to do this
Well, you don't have to, but why you wouldn't I don't know.
plus it gives us a get-out-of-jail-free card in the future if we need to change things
See you should have started with this argument :)
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.
Ha!
src/libcore/yk_swt_impl.c
Outdated
|
||
return ret_trace; | ||
} | ||
|
||
// Call this to safely mark the trace invalid. | ||
// We don't free the trace buffer here, as this may be called in a signal handler |
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.
The second sentence should be inside the function IMHO: it's not something that affects the caller.
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.
Agreed.
Give this a shot. |
Please squash. |
1f31122
to
6d83393
Compare
Like so |
Could we beef up the main commit message a bit, with some rough details of how things work? |
6d83393
to
5ebb7f3
Compare
Try that. |
"We try to handle the case where the Rust stack overflow detector's signal handler interrupts a trace" We don't just try -- we do handle that case! Can you maybe add in a bit about what an "invalidated trace" is, and how we might hit it? |
5ebb7f3
to
fd1aef1
Compare
Try this. |
Good stuff! bors r+ |
4: Software Trace Function in C. r=ltratt a=vext01 This is a DNMY (do no merge yet) PR. It needs some discussion. As discussed earlier this week, this is an attempt to implement the tracing function in C so that our MIR pass doesn't see the innards of the tracing mechanisms and it's dependencies. This means we can trace a lot more than we could have before, where e.g. thread locals and vectors used in the tracing mechanism were blocked from being traced. I printed the trace from one of my tests, and it looks highly plausable (tm): ``` MirLoc { crate_hash: 7687613001418581878, def_idx: 14, bb_idx: 1 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 0 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 1 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 2 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 3 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 6 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 7 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 8 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 9 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 2 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 3 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 6 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 7 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 8 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 9 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 2 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 3 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 6 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 7 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 8 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 9 } ... ``` I can see a loop! # Discussion Points ## Low-level of abstraction. Because the tracing function is now in C, and because we no longer need `Vec` or `std::thread` from `libstd` to trace, I opted to move the whole mechanism into `libcore`. This is better in the sense that we can trace stuff even if libstd isn't present (a dependency of the crate being traced). On the other hand, working in libcore is limiting and it's evident from the low level of abstraction in the API you see. I'd have liked to, for example, have given the user an iterator and a `Drop` implementation for the trace struct, but these are `libstd` concepts. I propose that in the next PR we make the libcore interface even more low-level -- make `stop_tracing` return a tuple, not a struct -- and then move the trace struct up into `libstd` where it can have better abstraction. This should mean that VM authors get a nice API to start and stop tracing via libstd, but they can still trace `no_std` crates that their VMs might depend upon. ## Traits Looking to the future, we will eventually have two backends (sw/hw) and a compile time switch to choose one. I suspect that we will want to offer the same API regardless of the backend, so we probably want a place to keep the common parts (e.g. `struct MirLoc` can probably be shared) and a trait for the API which includes stuff like getting an iterator over a trace. This should be a PR in the near future. ## C Errors Currently the C tracing code will crash hard (with `err()` or `errx()`) if there is an error. We could implement something like we did in hwtracer where each FFI call passes down an error struct pointer, which can be read by Rust after the call. Since this change can be hidden from the user in abstractions, I think this is low-priority for now. Do you agree with the above plan? Cheers Co-authored-by: Edd Barrett <[email protected]>
Damn "a trace is invalidated is when". Let me cancel bors and fix this. |
Build failed |
OK. |
This is implemented in C because if it were implemented in Rust, then the tracer code would trace itself and everything it calls (or we'd end up annotating a lot of the standard library `#[no_trace]`). With each call to the trace recorder, we build a "MIR location" struct from the call arguments and insert this into a thread local trace buffer. A successful tracing session will return the trace buffer to the consumer when we stop tracing. If however something happens which renders the trace data unreliable, we say the trace was "invalidated" and return NULL. For example, a trace is invalidated when the Rust stack overflow detector's signal handler interrupts a trace. A trace is also invalidated when when the trace buffer can't be a allocated or re-allocated. User signal handlers remain an open problem, as we are unable to force code outside of our hands to invalidate a trace.
Since the software tracing function is now implemented in C, tracing no longer interferes in these tests.
fd1aef1
to
12a2499
Compare
You can kick bors again now |
bors r+ |
4: Software Trace Function in C. r=ltratt a=vext01 This is a DNMY (do no merge yet) PR. It needs some discussion. As discussed earlier this week, this is an attempt to implement the tracing function in C so that our MIR pass doesn't see the innards of the tracing mechanisms and it's dependencies. This means we can trace a lot more than we could have before, where e.g. thread locals and vectors used in the tracing mechanism were blocked from being traced. I printed the trace from one of my tests, and it looks highly plausable (tm): ``` MirLoc { crate_hash: 7687613001418581878, def_idx: 14, bb_idx: 1 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 0 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 1 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 2 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 3 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 6 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 7 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 8 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 9 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 2 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 3 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 6 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 7 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 8 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 9 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 2 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 3 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 6 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 7 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 8 } MirLoc { crate_hash: 7687613001418581878, def_idx: 16, bb_idx: 9 } ... ``` I can see a loop! # Discussion Points ## Low-level of abstraction. Because the tracing function is now in C, and because we no longer need `Vec` or `std::thread` from `libstd` to trace, I opted to move the whole mechanism into `libcore`. This is better in the sense that we can trace stuff even if libstd isn't present (a dependency of the crate being traced). On the other hand, working in libcore is limiting and it's evident from the low level of abstraction in the API you see. I'd have liked to, for example, have given the user an iterator and a `Drop` implementation for the trace struct, but these are `libstd` concepts. I propose that in the next PR we make the libcore interface even more low-level -- make `stop_tracing` return a tuple, not a struct -- and then move the trace struct up into `libstd` where it can have better abstraction. This should mean that VM authors get a nice API to start and stop tracing via libstd, but they can still trace `no_std` crates that their VMs might depend upon. ## Traits Looking to the future, we will eventually have two backends (sw/hw) and a compile time switch to choose one. I suspect that we will want to offer the same API regardless of the backend, so we probably want a place to keep the common parts (e.g. `struct MirLoc` can probably be shared) and a trait for the API which includes stuff like getting an iterator over a trace. This should be a PR in the near future. ## C Errors Currently the C tracing code will crash hard (with `err()` or `errx()`) if there is an error. We could implement something like we did in hwtracer where each FFI call passes down an error struct pointer, which can be read by Rust after the call. Since this change can be hidden from the user in abstractions, I think this is low-priority for now. Do you agree with the above plan? Cheers Co-authored-by: Edd Barrett <[email protected]>
Build succeeded |
update from origin 2020-06-18
This is a combination of 18 commits. Commit softdevteam#2: Additional examples and some small improvements. Commit softdevteam#3: fixed mir-opt non-mir extensions and spanview title elements Corrected a fairly recent assumption in runtest.rs that all MIR dump files end in .mir. (It was appending .mir to the graphviz .dot and spanview .html file names when generating blessed output files. That also left outdated files in the baseline alongside the files with the incorrect names, which I've now removed.) Updated spanview HTML title elements to match their content, replacing a hardcoded and incorrect name that was left in accidentally when originally submitted. Commit softdevteam#4: added more test examples also improved Makefiles with support for non-zero exit status and to force validation of tests unless a specific test overrides it with a specific comment. Commit softdevteam#5: Fixed rare issues after testing on real-world crate Commit softdevteam#6: Addressed PR feedback, and removed temporary -Zexperimental-coverage -Zinstrument-coverage once again supports the latest capabilities of LLVM instrprof coverage instrumentation. Also fixed a bug in spanview. Commit softdevteam#7: Fix closure handling, add tests for closures and inner items And cleaned up other tests for consistency, and to make it more clear where spans start/end by breaking up lines. Commit softdevteam#8: renamed "typical" test results "expected" Now that the `llvm-cov show` tests are improved to normally expect matching actuals, and to allow individual tests to override that expectation. Commit softdevteam#9: test coverage of inline generic struct function Commit softdevteam#10: Addressed review feedback * Removed unnecessary Unreachable filter. * Replaced a match wildcard with remining variants. * Added more comments to help clarify the role of successors() in the CFG traversal Commit softdevteam#11: refactoring based on feedback * refactored `fn coverage_spans()`. * changed the way I expand an empty coverage span to improve performance * fixed a typo that I had accidently left in, in visit.rs Commit softdevteam#12: Optimized use of SourceMap and SourceFile Commit softdevteam#13: Fixed a regression, and synched with upstream Some generated test file names changed due to some new change upstream. Commit softdevteam#14: Stripping out crate disambiguators from demangled names These can vary depending on the test platform. Commit softdevteam#15: Ignore llvm-cov show diff on test with generics, expand IO error message Tests with generics produce llvm-cov show results with demangled names that can include an unstable "crate disambiguator" (hex value). The value changes when run in the Rust CI Windows environment. I added a sed filter to strip them out (in a prior commit), but sed also appears to fail in the same environment. Until I can figure out a workaround, I'm just going to ignore this specific test result. I added a FIXME to follow up later, but it's not that critical. I also saw an error with Windows GNU, but the IO error did not specify a path for the directory or file that triggered the error. I updated the error messages to provide more info for next, time but also noticed some other tests with similar steps did not fail. Looks spurious. Commit softdevteam#16: Modify rust-demangler to strip disambiguators by default Commit softdevteam#17: Remove std::process::exit from coverage tests Due to Issue #77553, programs that call std::process::exit() do not generate coverage results on Windows MSVC. Commit softdevteam#18: fix: test file paths exceeding Windows max path len
Don't run `resolve_vars_if_possible` in `normalize_erasing_regions` Neither `@eddyb` nor I could figure out what this was for. I changed it to `assert_eq!(normalized_value, infcx.resolve_vars_if_possible(&normalized_value));` and it passed the UI test suite. <details><summary> Outdated, I figured out the issue - `needs_infer()` needs to come _after_ erasing the lifetimes </summary> Strangely, if I change it to `assert!(!normalized_value.needs_infer())` it panics almost immediately: ``` query stack during panic: #0 [normalize_generic_arg_after_erasing_regions] normalizing `<str::IsWhitespace as str::pattern::Pattern>::Searcher` #1 [needs_drop_raw] computing whether `str::iter::Split<str::IsWhitespace>` needs drop softdevteam#2 [mir_built] building MIR for `str::<impl str>::split_whitespace` softdevteam#3 [unsafety_check_result] unsafety-checking `str::<impl str>::split_whitespace` softdevteam#4 [mir_const] processing MIR for `str::<impl str>::split_whitespace` softdevteam#5 [mir_promoted] processing `str::<impl str>::split_whitespace` softdevteam#6 [mir_borrowck] borrow-checking `str::<impl str>::split_whitespace` softdevteam#7 [analysis] running analysis passes on this crate end of query stack ``` I'm not entirely sure what's going on - maybe the two disagree? </details> For context, this came up while reviewing rust-lang/rust#77467 (cc `@lcnr).` Possibly this needs a crater run? r? `@nikomatsakis` cc `@matthewjasper`
This is a DNMY (do no merge yet) PR. It needs some discussion.
As discussed earlier this week, this is an attempt to implement the tracing function in C so that our MIR pass doesn't see the innards of the tracing mechanisms and it's dependencies.
This means we can trace a lot more than we could have before, where e.g. thread locals and vectors used in the tracing mechanism were blocked from being traced.
I printed the trace from one of my tests, and it looks highly plausable (tm):
I can see a loop!
Discussion Points
Low-level of abstraction.
Because the tracing function is now in C, and because we no longer need
Vec
orstd::thread
fromlibstd
to trace, I opted to move the whole mechanism intolibcore
. This is better in the sense that we can trace stuff even if libstd isn't present (a dependency of the crate being traced).On the other hand, working in libcore is limiting and it's evident from the low level of abstraction in the API you see. I'd have liked to, for example, have given the user an iterator and a
Drop
implementation for the trace struct, but these arelibstd
concepts.I propose that in the next PR we make the libcore interface even more low-level -- make
stop_tracing
return a tuple, not a struct -- and then move the trace struct up intolibstd
where it can have better abstraction.This should mean that VM authors get a nice API to start and stop tracing via libstd, but they can still trace
no_std
crates that their VMs might depend upon.Traits
Looking to the future, we will eventually have two backends (sw/hw) and a compile time switch to choose one. I suspect that we will want to offer the same API regardless of the backend, so we probably want a place to keep the common parts (e.g.
struct MirLoc
can probably be shared) and a trait for the API which includes stuff like getting an iterator over a trace.This should be a PR in the near future.
C Errors
Currently the C tracing code will crash hard (with
err()
orerrx()
) if there is an error. We could implement something like we did in hwtracer where each FFI call passes down an error struct pointer, which can be read by Rust after the call.Since this change can be hidden from the user in abstractions, I think this is low-priority for now.
Do you agree with the above plan?
Cheers