Commit graph

13 commits

Author SHA1 Message Date
Jean Boussier
664c23db79 GVL Instrumentation: remove the EXITED count assertion
It's very flaky for some unknown reason. Something we have
an extra EXITED event. I suspect some other test is causing this.
2022-07-13 19:39:31 +02:00
Jean Boussier
268269687c thread/test_instrumentation_api: cleanup all existing threads in setup
We saw the following failure:
```
TestThreadInstrumentation#test_thread_instrumentation [/tmp/ruby/v3/src/trunk-random3/test/-ext-/thread/test_instrumentation_api.rb:25]:
Expected 0..3 to include 4.
```

Which shouldn't happen unless somehow there was a leaked thread.
2022-07-13 14:13:41 +02:00
Nobuyoshi Nakada
0f8a0c5f37 Refactor tests for ThreadInstrumentation counters
* Extracted some assertions.
* Assert counter values should be positive.
2022-07-12 19:43:11 +09:00
Nobuyoshi Nakada
a6e2f3fd8d Use IO.popen to fork and exit the child process without cleanup 2022-07-12 19:43:11 +09:00
Nobuyoshi Nakada
f1c15f3e94
Relax assertion condition for thread local counters
Recently `TestThreadInstrumentation#test_join_counters` often fails as

```
<[1, 1, 1]> expected but was
<[2, 2, 2]>.
```

Probably it seems that the thread is suspended more than once.
There may be no guarantee that the subject thread never be suspended
more than once.
2022-07-08 10:55:44 +09:00
Jean Boussier
587d2d199b thread_pthread.c: call SUSPENDED event when entering native_sleep
[Bug #18900]

Thread#join and a few other codepaths are using native sleep as
a way to suspend the current thread. So we should call the relevant
hook when this happen, otherwise some thread may transition
directly from `RESUMED` to `READY`.
2022-07-07 17:49:00 +02:00
Jean Boussier
c46824d094 test_instrumentation_api.rb: Allow one less exit
I suspect that sometimes on CI the last thread is prempted before eaching the exit hook
causing the test to flake. I can't find a good way to force it to run.
2022-06-20 13:03:39 +02:00
Nobuyoshi Nakada
da362fee59
Scale the time to wait native threads to run hook 2022-06-19 23:33:26 +09:00
Jean Boussier
c34a5469c8 Debug TestThreadInstrumentation
It previously failed with:

```
    1) Failure:
  TestThreadInstrumentation#test_thread_instrumentation_fork_safe [/home/runner/work/ruby/ruby/src/test/-ext-/thread/test_instrumentation_api.rb:50]:
  <5> expected but was
  <4>.
```

Suggesting one `EXIT` event wasn't fired or processed.

Adding an assetion on `Thead#status` may help figure out what is wrong.
2022-06-17 15:11:10 +02:00
Jean Boussier
b6c1e1158d GVL Instrumentation API: add STARTED and EXITED events
[Feature #18339]

After experimenting with the initial version of the API I figured there is a need
for an exit event to cleanup instrumentation data. e.g. if you record data in a
{thread_id -> data} table, you need to free associated data when a thread goes away.
2022-06-17 09:08:26 +02:00
Jean Boussier
b1e6e58cd1 Refactor TestThreadInstrumentation to investigate CI flakiness
`test_thread_instrumentation_fork_safe` has been failing occasionaly
on Ubuntu and Arch. At this stage we're not sure why, all we know is
that the child exit with status 1.

I suspect that something entirely unrelated cause the forked children
to fail on exit, so by using `exit!(0)` and doing assertions in the
parent I hope to be resilient to that.
2022-06-07 13:19:34 +02:00
Yusuke Endoh
5d014bcb61 Use sleep 0.5 for tests of GVL instrumentation API
The tests fail randomly on some platforms.

20220605T213004Z.fail.html.gz
20220605T210003Z.fail.html.gz
```
[15737/21701] TestThreadInstrumentation#test_thread_instrumentation_fork_safe/home/chkbuild/chkbuild/tmp/build/20220605T213004Z/ruby/tool/lib/test/unit/assertions.rb:109:in `assert': Expected 0 to be nonzero?. (Test::Unit::AssertionFailedError)
```

The failures seem to depend on context switches. I suspect `sleep 0.05`
is too short, so this change tries to extend the wait time.
2022-06-06 12:52:15 +09:00
Jean Boussier
9125374726 [Feature #18339] GVL Instrumentation API
Ref: https://bugs.ruby-lang.org/issues/18339

Design:

- This tries to minimize the overhead when no hook is registered.
  It should only incur an extra unsynchronized boolean check.
- The hook list is protected with a read-write lock as to cause
  contention when some hooks are registered.
- The hooks MUST be thread safe, and MUST NOT call into Ruby as they
  are executed outside the GVL.
- It's simply a noop on Windows.

API:

```
rb_internal_thread_event_hook_t * rb_internal_thread_add_event_hook(rb_internal_thread_event_callback callback, rb_event_flag_t internal_event, void *user_data);
bool rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook);
```

You can subscribe to 3 events:

  - READY: called right before attempting to acquire the GVL
  - RESUMED: called right after successfully acquiring the GVL
  - SUSPENDED: called right after releasing the GVL.

The hooks MUST be threadsafe, as they are executed outside of the GVL, they also MUST NOT call any Ruby API.
2022-06-03 15:13:33 +02:00