-
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-7440] Use invoke location as a fallback for nameless threads in the profiler #2950
Merged
Conversation
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
The `thread_invoke_location` can be used as a fallback alternative for threads that have no name, and is what Ruby shows in `Thread#to_s` as well. This commit only gathers the invoke location and stores it in the context; this information is not yet propagated in the pprof, that will come in a later commit.
… the profiler **What does this PR do?**: Naming Ruby threads is optional, and a lot of Ruby code still creates threads and doesn't name them. As a workaround for Ruby threads that have no name, this PR makes the profiler use the "thread invoke location", which is what Ruby shows in the `to_s`/`inspect` of a thread, for instance: ``` [1] pry(main)> Thread.list.last.name => nil [2] pry(main)> Thread.list.last.to_s => "#<Thread:0x00005934cc0143e8 thread-name.rb:3 sleep>" ``` The "invoke location" is the file and line where the block that starts the thread is defined. **Motivation**: Having nameless threads is annoying because we show this information in several places of our UX, and with the timeline feature this will be even more visible. **Additional Notes**: Since Ruby doesn't have an API to get this information (other than calling `to_s` and then parsing its output), and because we want to avoid allocating any Ruby objects while the profiler is taking a sample, I chose to add to `private_vm_api_access.c` an API to get this information that is basically a heavily simplified version of `Thread#to_s`. **How to test the change?**: This change includes code coverage. Also, profile any app that starts and doesn't name threads, and you'll start seeing threads named "some_file.rb:some_line" in the profiler.
Arghhh old Rubies...
marcotc
reviewed
Jul 5, 2023
#ifndef NO_THREAD_INVOKE_ARG // Ruby 2.6+ | ||
if (thread->invoke_type != thread_invoke_type_proc) return NULL; | ||
|
||
VALUE proc = thread->invoke_arg.proc.proc; |
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.
proc proc proc
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.
proc proc? prooooc!
marcotc
reviewed
Jul 5, 2023
…le method This avoids doing the iseq lookup twice.
marcotc
approved these changes
Jul 6, 2023
ivoanjo
added a commit
that referenced
this pull request
Jul 24, 2023
…rted in native code **What does this PR do?**: This PR adds a fallback invoke location (which gets used as a name) for threads that a) Are unnamed, and b) Were started from native code. The added invoke location is the fixed string `(Unnamed thread from native gem)`. **Motivation**: We previously (in #2950) started using invoke location for threads that do not have a name BUT when a thread is started from native code it would have an empty name. Having an empty name is not particularly helpful, so I decided to instead have a simple placeholder that at least provides an hint on what the thread may be. **Additional Notes**: We don't yet do any resolving of symbols from native code, but in the future I guess we may try to see if the native code has a name at the C level, and use that as a fallback, but that's much more than a one-liner change :) **How to test the change?**: Change includes code coverage.
Merged
ivoanjo
added a commit
that referenced
this pull request
Oct 4, 2023
… gem is in use **What does this PR do?** In #2950, we added a fallback for nameless threads: we use their "invoke location", as shown by Ruby in the default `Thread#to_s`. The invoke location is the file and line of the first method of the thread. This fallback has an issue: when thread creation is monkey patched. One common source of this is the `logging` gem. When the `logging` gem monkey patches thread creation, every thread will have the same invoke location, which will point to the `logging` gem. This made the fallback invoke location worse than not having anything. To work around this, this PR changes the profiler so that when the invoke location belongs to the `logging` gem, it's not used, and a simpler `(Unnamed thread)` placeholder is used instead. **Motivation:** This issue came up when testing the timeline feature with some of the internal Ruby apps. **Additional Notes:** In the future we could probably explore a more generic fix (e.g. using `Thread.method(:new).source_location` or something like that to detect redefinition) but doing that from the profiler native code is a bit more work so I decided to go with a simpler approach. **How to test the change?** Change includes test coverage. You can also see the thread name difference on an app by creating a simple thread before/after loading the `logging` gem and see the fallback name for the thread.
2 tasks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What does this PR do?:
Naming Ruby threads is optional, and a lot of Ruby code still creates threads and doesn't name them.
As a workaround for Ruby threads that have no name, this PR makes the profiler use the "thread invoke location", which is what Ruby shows in the
to_s
/inspect
of a thread, for instance:The "invoke location" is the file and line where the block that starts the thread is defined (
thread-name.rb:3
for the example above).Motivation:
Having nameless threads is annoying because we show this information in several places of our UX, and with the timeline feature this will be even more visible.
Additional Notes:
Since Ruby doesn't have an API to get this information (other than calling
to_s
and then parsing its output), and because we want to avoid allocating any Ruby objects while the profiler is taking a sample, I chose to add toprivate_vm_api_access.c
an API to get this information that is basically a heavily simplified version ofThread#to_s
.How to test the change?:
This change includes code coverage. Also, profile any app that starts and doesn't name threads, and you'll start seeing threads named "some_file.rb:some_line" in the profiler.