gvl_timing 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6501413dc9601f05b7595fa0494ed21ef9de1638554ced822efb689f7970a51a
4
- data.tar.gz: 23ed94187a9048aa54bbbb33fcd20bbfa1c1e4169c788d65bcf4c9fc078ceedb
3
+ metadata.gz: 11943fd2bd229bb71b905436ff49735fa683355107e773798a0c265e91dc51c9
4
+ data.tar.gz: 28e2c52c9d4aa6eb9d9346c4bf85398c41d70f7cd8dfd70699f3618340779979
5
5
  SHA512:
6
- metadata.gz: dacfe66754ee03d97d509f8c6c30243675e0663e53616972628cd58c0b5b02d73f6943d0c3803e8879e1e9273031cb42ff9e06565d706ed21784df75ec166725
7
- data.tar.gz: c4c3be6acf8a456e604ee29016f2f129621e1508955dff64671cce172ea727272f83caf90367af235f9d0535597f1b22fedfd24f26358b38183f0f310769ca94
6
+ metadata.gz: ca21dea3e3d9d8bc9b4c46a76c32d33aa7e501f4b56c28f4543e46374e8e5341d90950dc18381f841011fd65cfbc4a47df280e5cec6297655991300574d31ac4
7
+ data.tar.gz: dfa75b00eac2c2c0e23d9c4acbb816a6c3f18224405bfacf40345c6d9d59e0ab22691f3697f70934ca13387520f050aa7d8fc3d706c1d6a2a1bc52cabc34b348
data/README.md CHANGED
@@ -1,24 +1,30 @@
1
- # GvlTiming
1
+ # gvl\_timing
2
2
 
3
- TODO: Delete this and the text below, and describe your gem
3
+ Measures timings for the current thread's GVL state for CRuby.
4
4
 
5
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/gvl_timing`. To experiment with that code, run `bin/console` for an interactive prompt.
5
+ This will add some (small) overhead to all GVL activity, so may be better to
6
+ development/test or sampled use rather than continuous timing.
6
7
 
7
8
  ## Installation
8
9
 
9
- TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
-
11
10
  Install the gem and add to the application's Gemfile by executing:
12
11
 
13
- $ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
14
-
15
- If bundler is not being used to manage dependencies, install the gem by executing:
16
-
17
- $ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
12
+ $ bundle add gvl_timing
18
13
 
19
14
  ## Usage
20
15
 
21
- TODO: Write usage instructions here
16
+ ```
17
+ >> timer = GVLTiming.measure { sleep 0.1 }
18
+ => #<GVLTiming::Timer total=0.10s running=0.00s idle=0.10s stalled=0.00s>
19
+ >> timer.duration
20
+ => 0.101082
21
+ >> timer.cpu_duration
22
+ => 7.4667e-05
23
+ >> timer.idle_duration
24
+ => 0.101048
25
+ >> timer.stalled_duration
26
+ => 1.0e-06
27
+ ```
22
28
 
23
29
  ## Development
24
30
 
@@ -7,4 +7,7 @@ require "mkmf"
7
7
  # selectively, or entirely remove this flag.
8
8
  append_cflags("-fvisibility=hidden")
9
9
 
10
+ have_header("ruby/thread.h")
11
+ have_struct_member("rb_internal_thread_event_data_t", "thread", ["ruby/thread.h"])
12
+
10
13
  create_makefile("gvl_timing/gvl_timing")
@@ -26,6 +26,8 @@ struct gvl_timer {
26
26
  uint64_t cputime_start;
27
27
  uint64_t cputime_stop;
28
28
 
29
+ uint64_t yields_count;
30
+
29
31
  uint64_t prev_timestamp;
30
32
  enum ruby_gvl_state prev_state;
31
33
  VALUE thread;
@@ -40,16 +42,23 @@ void record_timing(struct gvl_timer *timer, enum ruby_gvl_state new_state) {
40
42
  timer->timings[timer->prev_state] += (timestamp - timer->prev_timestamp);
41
43
  timer->prev_timestamp = timestamp;
42
44
  timer->prev_state = new_state;
45
+
46
+ if (new_state == GVL_STATE_IDLE) {
47
+ timer->yields_count++;
48
+ }
49
+
43
50
  }
44
51
 
45
52
  void internal_thread_event_cb(rb_event_flag_t event, const rb_internal_thread_event_data_t *event_data, void *data) {
46
53
  struct gvl_timer *timer = data;
47
54
 
55
+ VALUE thread;
56
+ #if HAVE_RB_INTERNAL_THREAD_EVENT_DATA_T_THREAD
57
+ thread = event_data->thread;
58
+ #else
48
59
  if (!ruby_native_thread_p()) return;
49
- VALUE thread = rb_thread_current();
50
- //#if HAVE_RB_INTERNAL_THREAD_EVENT_DATA_T_THREAD
51
- //#else
52
- //#endif
60
+ thread = rb_thread_current();
61
+ #endif
53
62
  if (thread != timer->thread) {
54
63
  return;
55
64
  }
@@ -150,6 +159,10 @@ VALUE gvl_timer_idle_duration(VALUE obj) {
150
159
  return ULL2NUM(get_timer(obj)->timings[GVL_STATE_IDLE]);
151
160
  }
152
161
 
162
+ VALUE gvl_timer_yields_count(VALUE obj) {
163
+ return ULL2NUM(get_timer(obj)->yields_count);
164
+ }
165
+
153
166
  RUBY_FUNC_EXPORTED void
154
167
  Init_gvl_timing(void)
155
168
  {
@@ -159,12 +172,14 @@ Init_gvl_timing(void)
159
172
  rb_define_method(rb_cTimer, "start", gvl_timer_start, 0);
160
173
  rb_define_method(rb_cTimer, "stop", gvl_timer_stop, 0);
161
174
 
162
- rb_define_method(rb_cTimer, "monotonic_start", gvl_timer_monotonic_start, 0);
163
- rb_define_method(rb_cTimer, "monotonic_stop", gvl_timer_monotonic_stop, 0);
164
- rb_define_method(rb_cTimer, "cputime_start", gvl_timer_cputime_start, 0);
165
- rb_define_method(rb_cTimer, "cputime_stop", gvl_timer_cputime_stop, 0);
175
+ rb_define_method(rb_cTimer, "monotonic_start_ns", gvl_timer_monotonic_start, 0);
176
+ rb_define_method(rb_cTimer, "monotonic_stop_ns", gvl_timer_monotonic_stop, 0);
177
+ rb_define_method(rb_cTimer, "cputime_start_ns", gvl_timer_cputime_start, 0);
178
+ rb_define_method(rb_cTimer, "cputime_stop_ns", gvl_timer_cputime_stop, 0);
179
+
180
+ rb_define_method(rb_cTimer, "running_duration_ns", gvl_timer_running_duration, 0);
181
+ rb_define_method(rb_cTimer, "stalled_duration_ns", gvl_timer_stalled_duration, 0);
182
+ rb_define_method(rb_cTimer, "idle_duration_ns", gvl_timer_idle_duration, 0);
166
183
 
167
- rb_define_method(rb_cTimer, "running_duration", gvl_timer_running_duration, 0);
168
- rb_define_method(rb_cTimer, "stalled_duration", gvl_timer_stalled_duration, 0);
169
- rb_define_method(rb_cTimer, "idle_duration", gvl_timer_idle_duration, 0);
184
+ rb_define_method(rb_cTimer, "yields_count", gvl_timer_yields_count, 0);
170
185
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GVLTiming
4
- VERSION = "0.1.2"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/gvl_timing.rb CHANGED
@@ -20,21 +20,60 @@ module GVLTiming
20
20
  class Timer
21
21
  NANOSECONDS_PER_SECOND_F = 1000000000.0
22
22
 
23
- def duration
24
- monotonic_stop - monotonic_start
23
+ def duration_ns
24
+ monotonic_stop_ns - monotonic_start_ns
25
25
  end
26
26
 
27
- def cpu_duration
28
- cputime_stop - cputime_start
27
+ def cpu_duration_ns
28
+ cputime_stop_ns - cputime_start_ns
29
29
  end
30
30
 
31
+ [
32
+ :duration, :cpu_duration,
33
+ :monotonic_start, :monotonic_stop,
34
+ :cputime_start, :cputime_stop,
35
+ :running_duration, :stalled_duration, :idle_duration
36
+ ].each do |name|
37
+ class_eval <<~RUBY
38
+ def #{name}(unit = :float_second)
39
+ scale_ns(#{name}_ns, unit)
40
+ end
41
+ RUBY
42
+ end
43
+
44
+ alias releases_count yields_count
45
+
31
46
  def inspect
32
- "#<#{self.class} total=%.2fs running=%.2fs idle=%.2fs stalled=%.2fs>" % [
33
- duration / NANOSECONDS_PER_SECOND_F,
34
- running_duration / NANOSECONDS_PER_SECOND_F,
35
- idle_duration / NANOSECONDS_PER_SECOND_F,
36
- stalled_duration / NANOSECONDS_PER_SECOND_F
47
+ "#<#{self.class} total=%.2fs running=%.2fs idle=%.2fs stalled=%.2fs yields=%d>" % [
48
+ duration,
49
+ running_duration,
50
+ idle_duration,
51
+ stalled_duration,
52
+ yields_count,
37
53
  ]
38
54
  end
55
+
56
+ private
57
+
58
+ def scale_ns(value_ns, unit)
59
+ case unit
60
+ when :float_second
61
+ value_ns / 1_000_000_000.0
62
+ when :float_millisecond
63
+ value_ns / 1_000_000.0
64
+ when :float_microsecond
65
+ value_ns / 1000.0
66
+ when :second
67
+ value_ns / 1_000_000_000
68
+ when :millisecond
69
+ value_ns / 1_000_000
70
+ when :microsecond
71
+ value_ns / 1000
72
+ when :nanosecond
73
+ value_ns
74
+ else
75
+ raise ArgumentError, "unexpected unit: #{unit.inspect}"
76
+ end
77
+ end
39
78
  end
40
79
  end
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gvl_timing
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Hawthorn
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-05-11 00:00:00.000000000 Z
10
+ date: 2025-04-18 00:00:00.000000000 Z
12
11
  dependencies: []
13
- description: Report time spent in different GVL states
12
+ description: Measure time spent in different GVL states
14
13
  email:
15
14
  - john@hawthorn.email
16
15
  executables:
@@ -36,7 +35,6 @@ metadata:
36
35
  homepage_uri: https://github.com/jhawthorn/gvl_timing
37
36
  source_code_uri: https://github.com/jhawthorn/gvl_timing
38
37
  changelog_uri: https://github.com/jhawthorn/gvl_timing
39
- post_install_message:
40
38
  rdoc_options: []
41
39
  require_paths:
42
40
  - lib
@@ -51,8 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
49
  - !ruby/object:Gem::Version
52
50
  version: '0'
53
51
  requirements: []
54
- rubygems_version: 3.4.19
55
- signing_key:
52
+ rubygems_version: 3.6.2
56
53
  specification_version: 4
57
- summary: Report time spent in different GVL states
54
+ summary: Measure time spent in different GVL states
58
55
  test_files: []