gvl-tracing 0.2.0 → 1.0.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: 1adc64642ec1cb371df66afa9f928cafe106349f981a3b8ec643232a0618b769
4
- data.tar.gz: 9b250c7a07df1f9a1f907100554fa74eba043edb639ad1cc777b33ba705d98f3
3
+ metadata.gz: 64d9b437af5f15e4a865a580486df67974e42b22b9836fa37e4de608597bf8d8
4
+ data.tar.gz: 52e7ecb9f89e613acd619a4225cfa2ac1f83cbf42e9173d59ccb91db09a1e7c6
5
5
  SHA512:
6
- metadata.gz: 5016d9734e5eeef9578fc83211bb68cbc26f68f1b93b41c3ff0fbd9f5a3b93745cb7de23c69cc228a903b17db565ee369ec3d41f7d9575e3107a04a9bf6368a0
7
- data.tar.gz: 821d89427465c6496e09a773a1277d35388d4205fd5e0e5f054fd8da8d1a46d902e4f464764a0e5891bb9ebb63451295ea2bf1986c085616b2ff60926dcbde7a
6
+ metadata.gz: 529be0892156b7060427359d3e4386ed4f2bf0d96a3671896a6fcde4d347370e061567b8f88718ec894520ff9dc4b3bc667810da6d16b3ed171ef004ea3ecaf3
7
+ data.tar.gz: 8702d542f6962be8f0b471ed15e66c6ff4da1a41eadd121edacb3ade280109eeb219b4b7a6c1786ba13518948406f5182102af1fc363c7327e9a3c5bfe5e2cd4
data/README.adoc CHANGED
@@ -10,7 +10,7 @@ image::preview.png[]
10
10
 
11
11
  See my blog post https://ivoanjo.me/blog/2022/07/17/tracing-ruby-global-vm-lock/[tracing ruby's (global) vm lock] for more details!
12
12
 
13
- NOTE: This gem only works on Ruby 3.2 and above because it depends on the new https://github.com/ruby/ruby/pull/5500[GVL Instrumentation API]. See below for an easy way to run Ruby 3.2 inside docker.
13
+ NOTE: This gem only works on Ruby 3.2 and above because it depends on the https://github.com/ruby/ruby/pull/5500[GVL Instrumentation API].
14
14
 
15
15
  == Quickest start
16
16
 
@@ -43,26 +43,6 @@ To do so:
43
43
  1. Download link:https://github.com/ivoanjo/gvl-tracing/blob/master/examples/example1.json.gz?raw=true[`examples/example1.json.gz`]
44
44
  2. Navigate to https://ui.perfetto.dev/ and use the **Open trace file** option to load the file
45
45
 
46
- == Quick start using docker
47
-
48
- The `gvl-tracing` gem requires Ruby 3.2, which is still under development. If you have docker installed on your machine, you can use the https://hub.docker.com/r/rubylang/ruby[ruby-lang development images] to try it out.
49
-
50
- Here's how you can use them:
51
-
52
- [source,bash]
53
- ----
54
- $ cd my_ruby_app/
55
- $ docker run -v $(pwd):/app -it rubylang/ruby:master-focal
56
- root@0e0b07edf906:/# cd app/
57
- root@0e0b07edf906:/app# ruby -v
58
- ruby 3.2.0dev (2022-07-23T12:42:05Z master 721d154e2f) [x86_64-linux]
59
- root@0e0b07edf906:/app# gem install gvl-tracing
60
- Building native extensions. This could take a while...
61
- Successfully installed gvl-tracing-0.1.1
62
- 1 gem installed
63
- root@0e0b07edf906:/app# ruby <your app>
64
- ----
65
-
66
46
  == Installation
67
47
 
68
48
  Install the gem and add to the application's `Gemfile` or `gems.rb` file by executing:
@@ -32,4 +32,10 @@ end
32
32
 
33
33
  require "mkmf"
34
34
 
35
+ have_func("gettid", "unistd.h")
36
+ have_header("pthread.h")
37
+ have_func("pthread_getname_np", "pthread.h")
38
+ have_func("pthread_threadid_np", "pthread.h")
39
+
40
+ create_header
35
41
  create_makefile "gvl_tracing_native_extension"
@@ -31,6 +31,16 @@
31
31
  #include <stdbool.h>
32
32
  #include <sys/types.h>
33
33
 
34
+ #include "extconf.h"
35
+
36
+ #ifdef HAVE_PTHREAD_H
37
+ #include <pthread.h>
38
+ #endif
39
+
40
+ #ifdef HAVE_GETTID
41
+ #include <unistd.h>
42
+ #endif
43
+
34
44
  static VALUE tracing_start(VALUE _self, VALUE output_path);
35
45
  static VALUE tracing_stop(VALUE _self);
36
46
  static double timestamp_microseconds(void);
@@ -59,12 +69,31 @@ void Init_gvl_tracing_native_extension(void) {
59
69
  rb_define_singleton_method(gvl_tracing_module, "stop", tracing_stop, 0);
60
70
  }
61
71
 
62
- static inline unsigned int current_thread_id(void) {
63
- if (!current_thread_serial_set) {
64
- current_thread_serial_set = true;
65
- current_thread_serial = RUBY_ATOMIC_FETCH_ADD(thread_serial, 1);
66
- }
67
- return (unsigned int)current_thread_serial;
72
+ static inline void initialize_thread_id(void) {
73
+ current_thread_serial_set = true;
74
+ current_thread_serial = RUBY_ATOMIC_FETCH_ADD(thread_serial, 1);
75
+ }
76
+
77
+ static inline void render_thread_metadata(void) {
78
+ uint64_t native_thread_id = 0;
79
+ #ifdef HAVE_GETTID
80
+ native_thread_id = gettid();
81
+ #elif HAVE_PTHREAD_THREADID_NP
82
+ pthread_threadid_np(pthread_self(), &native_thread_id);
83
+ #else
84
+ native_thread_id = current_thread_serial; // TODO: Better fallback for Windows?
85
+ #endif
86
+
87
+ char native_thread_name_buffer[64] = "(unnamed)";
88
+
89
+ #ifdef HAVE_PTHREAD_GETNAME_NP
90
+ pthread_getname_np(pthread_self(), native_thread_name_buffer, sizeof(native_thread_name_buffer));
91
+ #endif
92
+
93
+ fprintf(output_file,
94
+ " {\"ph\": \"M\", \"pid\": %u, \"tid\": %u, \"name\": \"thread_name\", \"args\": {\"name\": \"%lu %s\"}},\n",
95
+ process_id, current_thread_serial, native_thread_id, native_thread_name_buffer
96
+ );
68
97
  }
69
98
 
70
99
  static VALUE tracing_start(VALUE _self, VALUE output_path) {
@@ -134,7 +163,13 @@ static double timestamp_microseconds(void) {
134
163
  static void render_event(const char *event_name) {
135
164
  // Event data
136
165
  double now_microseconds = timestamp_microseconds() - started_tracing_at_microseconds;
137
- unsigned int thread_id = current_thread_id();
166
+
167
+ if (!current_thread_serial_set) {
168
+ initialize_thread_id();
169
+ render_thread_metadata();
170
+ }
171
+
172
+ unsigned int thread_id = current_thread_serial;
138
173
 
139
174
  // Each event is converted into two events in the output: one that signals the end of the previous event
140
175
  // (whatever it was), and one that signals the start of the actual event we're processing.
data/gvl-tracing.gemspec CHANGED
@@ -36,13 +36,13 @@ Gem::Specification.new do |spec|
36
36
  spec.summary = "Get a timeline view of Global VM Lock usage in your Ruby app"
37
37
  spec.homepage = "https://github.com/ivoanjo/gvl-tracing"
38
38
  spec.license = "MIT"
39
- spec.required_ruby_version = ">= 3.2.0.dev"
39
+ spec.required_ruby_version = ">= 3.2.0"
40
40
 
41
41
  # Specify which files should be added to the gem when it is released.
42
42
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
43
43
  spec.files = Dir.chdir(__dir__) do
44
44
  `git ls-files -z`.split("\x0").reject do |f|
45
- (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
45
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|examples)/|\.(?:git|travis|circleci)|appveyor)})
46
46
  end
47
47
  end
48
48
  spec.require_paths = ["lib", "ext"]
@@ -26,5 +26,5 @@
26
26
  # frozen_string_literal: true
27
27
 
28
28
  module GvlTracing
29
- VERSION = "0.2.0"
29
+ VERSION = "1.0.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: 0.2.0
4
+ version: 1.0.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: 2022-07-27 00:00:00.000000000 Z
11
+ date: 2023-02-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -24,14 +24,6 @@ files:
24
24
  - LICENSE
25
25
  - README.adoc
26
26
  - Rakefile
27
- - examples/example1.json.gz
28
- - examples/example1.rb
29
- - examples/example2.json.gz
30
- - examples/example2.rb
31
- - examples/example3.json.gz
32
- - examples/example3.rb
33
- - examples/gc.json.gz
34
- - examples/gc.rb
35
27
  - ext/gvl_tracing_native_extension/extconf.rb
36
28
  - ext/gvl_tracing_native_extension/gvl_tracing.c
37
29
  - gems.rb
@@ -52,14 +44,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
52
44
  requirements:
53
45
  - - ">="
54
46
  - !ruby/object:Gem::Version
55
- version: 3.2.0.dev
47
+ version: 3.2.0
56
48
  required_rubygems_version: !ruby/object:Gem::Requirement
57
49
  requirements:
58
50
  - - ">="
59
51
  - !ruby/object:Gem::Version
60
52
  version: '0'
61
53
  requirements: []
62
- rubygems_version: 3.4.0.dev
54
+ rubygems_version: 3.4.1
63
55
  signing_key:
64
56
  specification_version: 4
65
57
  summary: Get a timeline view of Global VM Lock usage in your Ruby app
Binary file
data/examples/example1.rb DELETED
@@ -1,18 +0,0 @@
1
- require "gvl-tracing"
2
-
3
- def fib(n)
4
- return n if n <= 1
5
- fib(n - 1) + fib(n - 2)
6
- end
7
-
8
- GvlTracing.start("example1.json")
9
-
10
- Thread.new { sleep(0.05) while true }
11
-
12
- sleep(0.05)
13
-
14
- 3.times.map { Thread.new { fib(37) } }.map(&:join)
15
-
16
- sleep(0.05)
17
-
18
- GvlTracing.stop
Binary file
data/examples/example2.rb DELETED
@@ -1,14 +0,0 @@
1
- require "gvl-tracing"
2
-
3
- def fib(n)
4
- return n if n <= 1
5
- fib(n - 1) + fib(n - 2)
6
- end
7
-
8
- GvlTracing.start("example2.json")
9
-
10
- other_thread = Thread.new { fib(37) } # runs in other thread
11
- fib(37) # runs in main thread
12
-
13
- other_thread.join
14
- GvlTracing.stop
Binary file
data/examples/example3.rb DELETED
@@ -1,14 +0,0 @@
1
- require "gvl-tracing"
2
-
3
- def fib(n)
4
- return n if n <= 1
5
- fib(n - 1) + fib(n - 2)
6
- end
7
-
8
- GvlTracing.start("example3.json")
9
-
10
- other_ractor = Ractor.new { fib(37) } # runs in other ractor
11
- fib(37) # runs in main thread
12
-
13
- other_ractor.take
14
- GvlTracing.stop
data/examples/gc.json.gz DELETED
Binary file
data/examples/gc.rb DELETED
@@ -1,13 +0,0 @@
1
- require "gvl-tracing"
2
-
3
- def alloc(n)
4
- n.times { Object.new }
5
- end
6
-
7
- GvlTracing.start("gc.json")
8
-
9
- 3.times.map { Thread.new { alloc(100_000) } }.map(&:join)
10
-
11
- sleep(0.05)
12
-
13
- GvlTracing.stop