You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We want to look into extending our Profiling product with support for Ruby.
On other platforms, we used an existing profiler as a starting point or completely relied on external packages.
When a txn starts, a new profiling_sample_rate, which works in relation to traces_sample_rate, determines if this txn should be profiled. Our default sample rate on other platforms is 101Hz.
On finish, we convert the raw output to our own profiling format and attach it as a profile envelope item to the transaction.
https://github.com/rbspy/rbspy might be worth looking into, as it's a sampling profiler that also supports outputting a speedscope compatible format, something our own format is derived from.
@sl0thentr0py agree with this, we can't use an external process and we can't use a deterministic (non-sampling) profiler, so stackprof seems like a reasonable choice. Are there any other options for in-process sampling profilers?
For Rails/Rack apps, I think we can use Shopify's app_profiler.
At the first glance:
It's a gem with native Rails integration
It also provides a Rack middleware or can be invoked with a block
It's still actively maintained
It's battle-tested at Shopify
However, I don't have much experience profiling in production either. So we'll need to do some testing with it ourselves, but do we have a good application/partner for that?
Ah sorry I didn't notice app_profiler is based on stackprof 🤦♂️
sample profile from that
That looks amazing.
it does not include threading info on the captured stacks
Can you explain more on this?
patch stackprof upstream / fork to send threading info somehow
Given that we don't have experience writing profilers yet, maybe we can go with this first? Even if the result is not accepted by the upstream, at least we'll know more on what we actually want to do and/or can do.
In a multi-threaded server like puma, there's stuff happening on each thread, and our Sample structure takes a thread_id so you can record and store call stacks from each thread.
Here's the thread switcher in the UI from a multi-threaded python profile.
For the first MVP, we decided that we will just go with a limited single thread use case, i.e. Stackprof can only run on one thread at a time and will early return if already running. Eventually based on adoption, we might invest time in doing something similar to stackprofx above. :)
I also fixed some timing issues (but still having some more spurious samples that I'm trying to debug). I'll post some better profiles once everything's done.
If you're curious, I also tried out some simple multi-threaded use cases below with this code.
Activity
sl0thentr0py commentedon Mar 6, 2023
notes
rbspywill probably be the most performant but is an external binary so it's mostly outindragiek commentedon Mar 6, 2023
@sl0thentr0py agree with this, we can't use an external process and we can't use a deterministic (non-sampling) profiler, so
stackprofseems like a reasonable choice. Are there any other options for in-process sampling profilers?sl0thentr0py commentedon Mar 6, 2023
not that I know of or can find, @st0012 do you know any other ones?
The table here is a good survey of the ruby profiler landscape
https://jvns.ca/blog/2017/12/17/how-do-ruby---python-profilers-work-/
st0012 commentedon Mar 14, 2023
For Rails/Rack apps, I think we can use Shopify's app_profiler.
At the first glance:
However, I don't have much experience profiling in production either. So we'll need to do some testing with it ourselves, but do we have a good application/partner for that?
sl0thentr0py commentedon Mar 22, 2023
copypasta from internal convo for public documentation
given this, how do we want to proceed? Options are:
st0012 commentedon Mar 22, 2023
Ah sorry I didn't notice
app_profileris based onstackprof🤦♂️That looks amazing.
Can you explain more on this?
Given that we don't have experience writing profilers yet, maybe we can go with this first? Even if the result is not accepted by the upstream, at least we'll know more on what we actually want to do and/or can do.
sl0thentr0py commentedon Mar 27, 2023
yes of course and thanks for the feedback!
In a multi-threaded server like puma, there's stuff happening on each thread, and our
Samplestructure takes athread_idso you can record and store call stacks from each thread.Here's the thread switcher in the UI from a multi-threaded python profile.
How stackprof works (in
:wallmode) isStackprof.startwas called from intarget_threadand forwards the incomingSIGALRMsignal to that threadrb_profile_framesAPI to record the call stack in that current threadFor the first MVP, we decided that we will just go with a limited single thread use case, i.e. Stackprof can only run on one thread at a time and will early return if already running. Eventually based on adoption, we might invest time in doing something similar to
stackprofxabove. :)sl0thentr0py commentedon Mar 27, 2023
I also fixed some timing issues (but still having some more spurious samples that I'm trying to debug). I'll post some better profiles once everything's done.
If you're curious, I also tried out some simple multi-threaded use cases below with this code.
transaction on main thread
https://sentry-sdks.sentry.io/profiling/profile/sentry-ruby/6cde0f4d2f2f405a9246d1f93c8e836b/flamechart/?colorCoding=by+system+vs+application+frame&query=&sorting=call+order&tid=42&view=top+down
transaction on child thread
https://sentry-sdks.sentry.io/profiling/profile/sentry-ruby/3794ecdb8ad84140af610646017422c0/flamechart/?colorCoding=by+system+vs+application+frame&query=&sorting=call+order&tid=42&view=top+down
as you can see, we always record call stacks from the thread
Stackprof.startis called on.sl0thentr0py commentedon Mar 28, 2023
opened issue upstream re: timing issues on puma
tmm1/stackprof#201
sl0thentr0py commentedon Apr 13, 2023
docs/wizard PRs: