-
Notifications
You must be signed in to change notification settings - Fork 19
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
Add minimal support for sampling #22
Conversation
@jimblandy I think this is ready for review. It shouldn't be merged until a new version of bytes is available with my upstream PR but that doesn't affect the code. |
@Phantomical This is very exciting. I will have time to review this on Friday. |
I don't agree - but I think it's fine to proceed as you suggest anyway. I do think we're going to need to be able to process data from files eventually. If we don't, then we basically force our users who also want to consume perf files to either use two separate crates, or switch entirely to some other crate that does support both use cases. But I don't see the work here as likely to cut off future possibilities, in practice. I'm pretty sure we're going to end up with a lot of code that doesn't care where the data came from, which can serve both live and recorded sources. I think we can just proceed with the work here and think about files later. |
I think we can just leave out the feature. We'll be bumping the major version anyway. |
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 wasn't able to get into the substance of this today, but here are a few minor comments I have so far:
perf-event/src/lib.rs
Outdated
impl std::ops::Deref for Sampler { | ||
type Target = Counter; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.counter | ||
} | ||
} | ||
|
||
impl std::ops::DerefMut for Sampler { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.counter | ||
} | ||
} |
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 way of making Sampler
support the operations of Counter
is considered an anti-pattern in Rust:
https://rust-unofficial.github.io/patterns/anti_patterns/deref.html
Possible alternatives:
- Add a
counter
method toSampler
, and let people call that to get the underlyingCounter
. - Create a trait with the methods, and have both
Sampler
andCounter
implement that.
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.
Unfortunately, both of those alternatives aren't great :(
As a third alternative:
- Copy the methods from
Counter
toSampler
and have them delegate to the real implementations inCounter
I think that either keeping the Deref
impls (despite it being an antipattern) or copying the methods is the best choice. Ultimately, though, the choice is yours and I'll implement whichever one you prefer.
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.
Just thinking this over: Some of the methods only make sense for counted events. Not all sampled events are counted events. But there are counters that record their overflows to the mmap area, so certainly Sampler
needs the counter-related methods. So I guess there's nothing that can be omitted.
Let's just copy the methods for now.
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've removed the deref impls and used a macro to add the methods to both Counter
and Sampler
.
This means we only need one #[cfg(feature = "unstable")] for the block instead of one per method.
A small println type example would help in understanding the API usage. |
@janaknat I agree. However, what's actually been added in this PR is almost too limited to do a proper example (beyond what is in the tests here). I will add that as one of the (many) follow-up PRs that I'll be making once this one gets merged. |
This adds nix as a dev-dependency so that it can be used to replace the direct libc calls within the test cases.
Bytes v1.3.0 has now been released with the @jimblandy this is now ready for final review and/or merging, whichever you think is appropriate. |
Clippy doesn't like having a method named `next` on a struct when it's not an implementation of Iterator. This silences the clippy warning by renaming the method.
The issue was a missing ! in the if guard on config.sample_id_all. This would cause SampleId to parse fields when _not_ expected to and ignore everything when it was expected to parse fields. This commit also includes some test cases to exercise both options.
These are present within perf_event.h but aren't documented in the manpage yet (not even the one for Linux 6.0).
This is also present within the source headers but undocumented in the manpage.
@jimblandy Do you think you'll have time to look at this anytime soon? |
@Phantomical Is there a branch in your repo which has all the changes for full sampling support that I can fork off of? I'd love to give it a run. |
@janaknat I do! I have everything up in a branch here: https://github.com/Phantomical/perf-event/tree/sampling-work. I haven't touched it in a few months but it is more or less feature complete. |
@Phantomical Thanks. I'll give it a go. |
@Phantomical Is it possible to create a Also, is there a source you used to fully understand the perf record functionality of perf_event_open()? I am looking at https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/perf.data-file-format.txt . Curious to know what you are using as reference. |
@janaknat It is technically possible but it might not be the best approach. As far as I know, The best documentation on |
Closing this in favour of #30 since I believe that to be a better approach. |
This PR introduces an absolutely minimal skeleton of an API for reading sampled perf events.
Highlights
Sampler
type which is a counter that can also readRecord
s from the kernel ring buffer.PERF_EVENT_MMAP
records and nothing else.This is just enough to write a simple mmap end-to-end test to check that the whole thing is working. The rest of the features can be added backwards-compatibly in follow-up PRs. See the non-goals section for stuff that I have excluded from this PR.
API Summary
This is just a subset of the API prototypes but since this PR is so large I felt that it would be helpful to have it summarized.
API Prototypes
How the API Works
Builder
like normal, configure it, and callBuilder::build_sampler
to create aSampler
.Sampler::next
orSampler::next_blocking
to read the nextsample::Record
out of the ring buffer.Record
for whatever profiling thing you wanted to do.Future Compatibility
This is important part of any binding to
perf_event_open
. Here's how this API can be extended in a semver compatible manner.RecordEvent
enum is#[non_exhaustive]
. When a new record type is added to the perf API then we can add support without having to break backwards compatibility. In the meantime, users can useRecordEvent::Unknown
to handle records thatperf-event
does not support.Record
: I don't think this one will happen but neverthelessRecord
is also#[non_exhaustive]
#[non_exhaustive]
as well.Non-goals for this specific PR
I'm trying to keep this PR as small as possible because it is already too big. Except for the last one, all of these can be added in follow-up PRs.
PERF_RECORD_MMAP
.perf_event_attr
.perf-event
needs.Supersedes #1