gvl-tracing 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5ec59682543834d531647bea2601457de0d8f8d57fe039181375891ef29ae60
4
- data.tar.gz: ebfa80876458868eb9780bdf655c75ff7c3b649f0661799533e6dcd12f5b06ea
3
+ metadata.gz: d4945e5419655b2e69f310845e6214ff0bd6eb66ae820383f9cbe97855f15cdb
4
+ data.tar.gz: dd95a9431c53c3904b054227a305da7433a789d8828b0340abc2b48864361735
5
5
  SHA512:
6
- metadata.gz: 259ae5c91f2d750ed61ec938a3eb3f92fc813391393420648288626d824408f1678a534de2185c73a6ea8fc2a695aa46135f5529a8fa9bd32e00c0f878b5a538
7
- data.tar.gz: ead5ce15933a39684675705a60983dbcd5fc8afb7752822103799261d05d5e3b3f6da8562ca496b9929f7bebf9ed203c31ccc5b778be59bf2c724f7bab9c4d49
6
+ metadata.gz: eca1b710f5918e887f06c44dfa970100e77c99bbc63318321a72e76dfffc4b44022b055dae4de05992494fc40910a467f4aa3ed045ab891018303a15fe8169e1
7
+ data.tar.gz: 59deb53b041211513979526345af62c3e94495e73deae38d1f1e7272a11469695ae5c2435331bcf811f1c943c18f9602c4e3199c97fef9963cb3e3e4cd25f5cd
@@ -56,11 +56,14 @@ static void set_native_thread_id(void);
56
56
  static void render_event(const char *event_name);
57
57
  static void on_thread_event(rb_event_flag_t event, const rb_internal_thread_event_data_t *_unused1, void *_unused2);
58
58
  static void on_gc_event(VALUE tpval, void *_unused1);
59
+ static VALUE mark_sleeping(VALUE _self);
59
60
 
60
61
  // Thread-local state
61
62
  static _Thread_local bool current_thread_seen = false;
62
63
  static _Thread_local unsigned int current_thread_serial = 0;
63
64
  static _Thread_local uint64_t thread_id = 0;
65
+ static _Thread_local rb_event_flag_t previous_state = 0; // Used to coalesce similar events
66
+ static _Thread_local bool sleeping = false; // Used to track when a thread is sleeping
64
67
 
65
68
  // Global mutable state
66
69
  static rb_atomic_t thread_serial = 0;
@@ -77,6 +80,7 @@ void Init_gvl_tracing_native_extension(void) {
77
80
 
78
81
  rb_define_singleton_method(gvl_tracing_module, "_start", tracing_start, 1);
79
82
  rb_define_singleton_method(gvl_tracing_module, "_stop", tracing_stop, 0);
83
+ rb_define_singleton_method(gvl_tracing_module, "mark_sleeping", mark_sleeping, 0);
80
84
  }
81
85
 
82
86
  static inline void initialize_thread_id(void) {
@@ -204,6 +208,23 @@ static void render_event(const char *event_name) {
204
208
  }
205
209
 
206
210
  static void on_thread_event(rb_event_flag_t event_id, UNUSED_ARG const rb_internal_thread_event_data_t *_unused1, UNUSED_ARG void *_unused2) {
211
+ // In some cases, Ruby seems to even multiple suspended events for the same thread in a row (e.g. when multiple threads)
212
+ // are waiting on a Thread::ConditionVariable.new that gets signaled. We coalesce these events to make the resulting
213
+ // timeline easier to see.
214
+ //
215
+ // I haven't observed other situations where we'd want to coalesce events, but we may apply this to all events in the
216
+ // future. One annoying thing to remember when generalizing this is how to reset the `previous_state` across multiple
217
+ // start/stop calls to GvlTracing.
218
+ if (event_id == RUBY_INTERNAL_THREAD_EVENT_SUSPENDED && event_id == previous_state) return;
219
+ previous_state = event_id;
220
+
221
+ if (event_id == RUBY_INTERNAL_THREAD_EVENT_SUSPENDED && sleeping) {
222
+ render_event("sleeping");
223
+ return;
224
+ } else {
225
+ sleeping = false;
226
+ }
227
+
207
228
  const char* event_name = "bug_unknown_event";
208
229
  switch (event_id) {
209
230
  case RUBY_INTERNAL_THREAD_EVENT_READY: event_name = "wants_gvl"; break;
@@ -224,3 +245,8 @@ static void on_gc_event(VALUE tpval, UNUSED_ARG void *_unused1) {
224
245
  }
225
246
  render_event(event_name);
226
247
  }
248
+
249
+ static VALUE mark_sleeping(VALUE _self) {
250
+ sleeping = true;
251
+ return Qnil;
252
+ }
@@ -0,0 +1,12 @@
1
+ # Experimental: This monkey patch when loaded introduces a new state -- "sleeping" -- which is more specific than the
2
+ # regular "waiting". This can be useful to distinguish when waiting is happening based on time, vs for some event to
3
+ # happen.
4
+
5
+ module GvlTracing::SleepTracking
6
+ def sleep(...)
7
+ GvlTracing.mark_sleeping
8
+ super(...)
9
+ end
10
+ end
11
+
12
+ include GvlTracing::SleepTracking
@@ -26,5 +26,5 @@
26
26
  # frozen_string_literal: true
27
27
 
28
28
  module GvlTracing
29
- VERSION = "1.3.0"
29
+ VERSION = "1.4.0"
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gvl-tracing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivo Anjo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-01 00:00:00.000000000 Z
11
+ date: 2023-09-05 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -30,6 +30,7 @@ files:
30
30
  - gems.rb
31
31
  - gvl-tracing.gemspec
32
32
  - lib/gvl-tracing.rb
33
+ - lib/gvl_tracing/sleep_tracking.rb
33
34
  - lib/gvl_tracing/version.rb
34
35
  - preview.png
35
36
  homepage: https://github.com/ivoanjo/gvl-tracing