-
Notifications
You must be signed in to change notification settings - Fork 375
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
[PROF-4904] First implementation of new Stack collector based on rb_profile_frames
API
#1966
[PROF-4904] First implementation of new Stack collector based on rb_profile_frames
API
#1966
Conversation
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.
open source aspects LGTM
9078e11
to
4be8f4f
Compare
31a46cf
to
5814cf1
Compare
898b439
to
6be9535
Compare
The Ruby sources usually use `rb_thread_t` so this brings us closer to upstream.
The `rb_profile_frames` method can be used to get stack traces for a profiler, but it has a number of limitations and caveats which we'll need to bridge, and thus we need to ship our own copy of it. This is OK since upstream Ruby allows the source code to be used under the terms of the BSD-2-Clause license, which I include in the file with the copied snippets. I'll also run this through the internal opensource group, in case they have any notes/concerns.
(The extraction originally came from `http_transport.c`, added in #1923 but after a rebase only the addition of the new header remained)
This header always needs to be included when including `private_vm_api_access.h` so it makes more sense to have it there.
These will be needed in the `collectors_stack.c`.
This first version has only a very limited test; this will be extended as we fix `rb_profile_frames` sharp edges in later commits.
Now that we have a component capable of writing stacks into the `StackRecorder` -- the `Collectors::Stack`, we can use it to write a stack and confirm that values and labels are correctly propagated.
5814cf1
to
9d35f1e
Compare
… in next PR) Making the stack collector work on older Rubies is quite a lot of work, which I'd like to submit as a separate PR. To avoid our CI breaking, let's disable a few profiler things, which we will re-enable in <#2000>. Note that *NONE* of the components being disabled or messed with are enabled for customers -- they're still not on in any situation -- so this strategy of disabling stuff is just an enabler for incremental development.
} | ||
|
||
void sample(VALUE thread, VALUE recorder_instance, ddprof_ffi_Slice_i64 metric_values, ddprof_ffi_Slice_label labels) { | ||
const int max_frames = 400; // FIXME: Should be configurable |
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 made configurable in a later PR.
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.
There's a performance argument to be made to keeping this a compile time constant, but I'd probably think it's unlikely to be worth the rigidness of this being unconfigurable.
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.
Possibly, yeah, especially because here I'm still doing stack allocation for the needed data. In the next PR (#2000) I move this over to being heap-allocated as stack allocation failure modes are... weird.
I do plan to benchmark and profile the new profiler code once it's all wired, to catch any obvious inefficiencies that may have been left :)
// The sources below are modified versions of code extracted from the Ruby project. | ||
// The Ruby project copyright and license follow: |
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.
Were there modifications to the source code we copied here?
If so, could you leave some inline comments around the code lines that were modified?
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.
Hopefully addressed in 4b7ee20:
- Added a note to document that every function has a list of changes (most of them are
Modifications: none
) - Added an inline comment in
ddtrace_rb_profile_frames
to point at what changed from the upstream version (addedthread
argument)
This PR adds the new
Stack
collector, which samples using therb_profile_frames
API.Rather than using the
rb_profile_frames
API directly, it copy pastes it from the Ruby VM sources into theprivate_vm_api_access.c
file.I claim license-wise this is OK since upstream Ruby allows the source code to be used under the terms of the BSD-2-Clause license, which I include in the file with the copied snippets as well as in the
LICENSE-3rdparty.csv
file as usual. I'll also run this through the internal opensource group, in case they have any notes/concerns.Code-wise, here's a quick description of
rb_profile_frames
and why we need it:What is rb_profile_frames?
rb_profile_frames
is a Ruby VM debug API added for use by profilers for sampling the stack trace of a Ruby thread.Its main other user is the stackprof profiler: https://github.com/tmm1/stackprof .
Why do we need a custom version of rb_profile_frames?
There are a few reasons:
thread, and to support wall-clock profiling we require sampling other threads. This is only safe because of the
Global VM Lock. (We don't yet support sampling Ractors beyond the main one; we'll need to find a way to do it
safely first.)
rb_profile_frames, and by making our own copy of this function we can extract more of this information.
See for backtracie gem (https://github.com/ivoanjo/backtracie) for an exploration of what can potentially be done.
private_vm_api_access.c
,our medium/long-term plan is to contribute upstream changes and make it so that we don't need any of this
on modern Rubies.
This PR depends on #1960. It also isn't the full story -- I tried to limit the scope of this PR to avoid it growing too much, since "copy pasting code from the Ruby codebase" was already a quite important event by itself.