diff options
author | Daisuke Aritomo <osyoyu@osyoyu.com> | 2023-09-29 15:35:36 +0900 |
---|---|---|
committer | Koichi Sasada <ko1@atdot.net> | 2023-10-31 11:16:18 +0900 |
commit | 4adf418be963b3554962b2f27057be81486c57d9 (patch) | |
tree | d43c3006925aaacdf522b58b752b860f6b94875a /test/-ext- | |
parent | 02ecc3c8550af1aab7916975e7019b2a3ffe8591 (diff) |
[Feature #10602] Add new API rb_profile_thread_frames()
Add a new API rb_profile_thread_frames(), which is essentialy a
per-thread version of rb_profile_frames().
While the original rb_profile_frames() always returns results about the
current active thread obtained by GET_EC(), this new API takes a Thread
to be profiled as an argument.
This should come in handy when profiling I/O-bound programs such as
webapps, since this new API allows us to learn about Threads performing
I/O (which do not have the GVL).
Profiling worker threads (such as Sidekiq workers) may be another
application.
Implements [Feature #10602]
Co-authored-by: Mike Perham <mike@perham.net>
Diffstat (limited to 'test/-ext-')
-rw-r--r-- | test/-ext-/debug/test_profile_frames.rb | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/test/-ext-/debug/test_profile_frames.rb b/test/-ext-/debug/test_profile_frames.rb index 08aedf63c8..e66413c228 100644 --- a/test/-ext-/debug/test_profile_frames.rb +++ b/test/-ext-/debug/test_profile_frames.rb @@ -39,6 +39,20 @@ class SampleClassForTestProfileFrames end end +class SampleClassForTestProfileThreadFrames + def initialize(mutex) + @mutex = mutex + end + + def foo(block) + bar(block) + end + + def bar(block) + block.call + end +end + class TestProfileFrames < Test::Unit::TestCase def test_profile_frames obj, frames = Fiber.new{ @@ -139,6 +153,39 @@ class TestProfileFrames < Test::Unit::TestCase } end + def test_profile_thread_frames + mutex = Mutex.new + th = Thread.new do + mutex.lock + Thread.stop + SampleClassForTestProfileThreadFrames.new(mutex).foo(lambda { mutex.unlock; loop { sleep(1) } } ) + end + + # ensure execution has reached SampleClassForTestProfileThreadFrames#bar before running profile_thread_frames + loop { break if th.status == "sleep"; sleep 0.1 } + th.run + mutex.lock # wait until SampleClassForTestProfileThreadFrames#bar has been called + + frames = Bug::Debug.profile_thread_frames(th, 0, 10) + + full_labels = [ + "Kernel#sleep", + "TestProfileFrames#test_profile_thread_frames", + "Kernel#loop", + "TestProfileFrames#test_profile_thread_frames", + "SampleClassForTestProfileThreadFrames#bar", + "SampleClassForTestProfileThreadFrames#foo", + "TestProfileFrames#test_profile_thread_frames", + ] + + frames.each.with_index do |frame, i| + assert_equal(full_labels[i], frame) + end + + th.kill + end + + def test_matches_backtrace_locations_main_thread assert_equal(Thread.current, Thread.main) |