vernier 0.2.1 → 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: dcfae18cfffd67e1e8a52c0c9de2654e7523b674d492964dfa3447c967d981e3
4
- data.tar.gz: 4ff2a81a37d19f974914a0ff3fa28937302a636721b8732f7e7b282f895db9f3
3
+ metadata.gz: 52f738e495accaaab1af3f33a806a7b20467aa8f2a93f4b7bf8d7300fdaf88ad
4
+ data.tar.gz: e6877e7315fb990e8db9482b940a96068770987989fec85a804c75ce79b62022
5
5
  SHA512:
6
- metadata.gz: bd4e4f001047bb3f20c9c0670339747b9e29abf6e44bcd77dbb38fcf7c16f42d33eef893045ab7a899b155d9b98765950e91af79864234a2d66243490d367d49
7
- data.tar.gz: 14cecc8aa1058b4e38f130bed6ec1d43e8a59a636c125862ef6c61df13f885e1d76b1a142d0fa8fab16ea6bfee2642b7cd606bb562020f800ce3518b2c7fac2c
6
+ metadata.gz: 4dcf1c2ebcbfcfd1b5a456fbc9ffbfd82da1f96622b8dc889d9ece105a9f461768dd688b6e0ee73102db104bff527a9c940f6d74689d520005ea216823444cbe
7
+ data.tar.gz: 97e0116ec7de5ee084512520debd37d0262555ca6a09d427b9147c3e08303492c925e8b1f81c9299915aff6322122a82e8737d1ef22823da8689aab2ce63aa6f
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Vernier
2
2
 
3
- Experimental next-generation Ruby profiler.
3
+ Experimental next-generation Ruby sampling profiler. Tracks multiple threads, GVL activity, GC pauses, idle time, and more.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,7 +18,7 @@ Record a flamegraph of all **retained** allocations from loading `irb`.
18
18
  ruby -r vernier -e 'Vernier.trace_retained(out: "irb_profile.json") { require "irb" }'
19
19
  ```
20
20
 
21
- The output can then be viewed in the [Firefox Profiler (demo)](https://share.firefox.dev/3DhLsFa)
21
+ The output can then be viewed in the [Firefox Profiler (demo)](https://share.firefox.dev/3DhLsFa) or the [`profile-viewer` gem](https://github.com/tenderlove/profiler/tree/ruby) (a Ruby-customized version of the firefox profiler.
22
22
 
23
23
  ![Screenshot 2023-07-16 at 21-06-19 Ruby_Vernier – 1970-01-01 12 00 00 a m UTC – Firefox Profiler](https://github.com/jhawthorn/vernier/assets/131752/9ca0b593-70fb-4c8b-aed9-cb33e0e0bc06)
24
24
 
data/bin/vernier ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ load "#{__dir__}/../exe/vernier"
@@ -0,0 +1,20 @@
1
+ ENV["MT_CPU"] = "3"
2
+
3
+ require "minitest/autorun"
4
+
5
+ class TestMeme < Minitest::Test
6
+ parallelize_me!
7
+
8
+ def test_sleeping
9
+ sleep 1
10
+ end
11
+
12
+ def test_also_sleeping
13
+ sleep 1
14
+ end
15
+
16
+ def test_prime
17
+ require "prime"
18
+ assert_equal 1299709, Prime.first(100000).last
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ def tarai(x, y, z) =
2
+ x <= y ? y : tarai(tarai(x-1, y, z),
3
+ tarai(y-1, z, x),
4
+ tarai(z-1, x, y))
5
+
6
+ require 'vernier'
7
+ Vernier.trace(out: "ractor.json") do
8
+ 4.times.map do
9
+ Ractor.new { tarai(14, 7, 0) }
10
+ end.each(&:take)
11
+ end
data/examples/rails.rb ADDED
@@ -0,0 +1,125 @@
1
+ require 'bundler/inline'
2
+
3
+ gemfile do
4
+ source 'https://rubygems.org'
5
+ rails_version = ENV["RAILS"]
6
+ case rails_version
7
+ when nil
8
+ gem "rails"
9
+ when "edge", "main"
10
+ gem "rails", github: "rails/rails"
11
+ when /\//
12
+ gem "rails", path: rails_version
13
+ else
14
+ gem "rails", rails_version
15
+ end
16
+ gem "sqlite3"
17
+ gem "vernier", path: "#{__dir__}/.."
18
+ end
19
+
20
+ require "action_controller"
21
+ require "action_view"
22
+ require "active_record"
23
+ require "rails"
24
+
25
+ ENV["RAILS_ENV"] = "production"
26
+
27
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
28
+ class MyApp < Rails::Application
29
+ config.load_defaults 7.0
30
+
31
+ config.eager_load = true
32
+ config.cache_classes = true
33
+ config.hosts << ->(_){ true }
34
+ config.secret_key_base = SecureRandom.hex
35
+ config.consider_all_requests_local = true
36
+ config.public_file_server.enabled = false
37
+ config.cache_store = :null_store
38
+ config.log_level = :warn
39
+ config.enable_site_error_reporting = false
40
+
41
+ logger = ActiveSupport::Logger.new(STDOUT)
42
+ logger.formatter = config.log_formatter
43
+ config.logger = ActiveSupport::TaggedLogging.new(logger)
44
+
45
+ routes.append do
46
+ root to: "home#show"
47
+ end
48
+
49
+ MyApp.initialize!
50
+ end
51
+
52
+ def silence(stream=STDOUT)
53
+ old = stream.dup
54
+ stream.reopen IO::NULL
55
+ yield
56
+ stream.reopen(old)
57
+ old.dup
58
+ end
59
+
60
+ silence do
61
+ ActiveRecord::Schema.define do
62
+ create_table :posts, force: true do |t|
63
+ t.string :title
64
+ t.text :body
65
+ t.integer :likes
66
+ end
67
+ create_table :comments, force: true do |t|
68
+ t.belongs_to :post
69
+ t.string :title
70
+ t.text :body
71
+ t.datetime :posted_at
72
+ end
73
+ end
74
+ end
75
+
76
+ class Post < ActiveRecord::Base
77
+ has_many :comments
78
+ end
79
+
80
+ class Comment < ActiveRecord::Base
81
+ belongs_to :post
82
+ end
83
+
84
+ 0.upto(100) do |i|
85
+ post = Post.create!(title: "Post number #{i}", body: "blog " * 50, likes: ((i * 1337) % 30))
86
+ 5.times do
87
+ post.comments.create!(post: post, title: "nice post!", body: "keep it up!", posted_at: Time.now)
88
+ end
89
+ end
90
+
91
+ class HomeController < ActionController::Base
92
+ def show
93
+ posts = Post.order(likes: :desc).includes(:comments).first(10)
94
+ render json: posts
95
+ end
96
+ end
97
+
98
+ app = Rails.application
99
+ env = Rack::MockRequest.env_for("http://example.org/")
100
+ make_request = -> () do
101
+ status, headers, body = app.call(env)
102
+ body.close if body.respond_to?(:close)
103
+ if status
104
+ end
105
+ body = body.each.to_a.join("")
106
+ raise body if status != 200
107
+ [status, headers, body]
108
+ end
109
+
110
+ # warm up
111
+ make_request.call
112
+
113
+ Vernier.trace(out: "rails.json") do |collector|
114
+ ActiveSupport::Notifications.monotonic_subscribe do |name, start, finish, id, payload|
115
+ collector.add_marker(
116
+ name:,
117
+ start: (start * 1_000_000_000).to_i,
118
+ finish: (finish * 1_000_000_000).to_i,
119
+ )
120
+ end
121
+
122
+ 1000.times do
123
+ make_request.call
124
+ end
125
+ end
data/exe/vernier ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+
5
+ banner = <<-END
6
+ Usage: vernier run [FLAGS] -- COMMAND
7
+
8
+ FLAGS:
9
+ END
10
+
11
+ options = {}
12
+ parser = OptionParser.new(banner) do |o|
13
+ o.on('--output [FILENAME]', String, "output filename") do |s|
14
+ options[:output] = s
15
+ end
16
+ o.on('--interval [MICROSECONDS]', Integer, "sampling interval (default 500)") do |i|
17
+ options[:interval] = i
18
+ end
19
+ o.on('--signal [NAME]', String, "specify a signal to start and stop the profiler") do |s|
20
+ options[:signal] = s
21
+ end
22
+ o.on('--start-paused', "don't automatically start the profiler") do
23
+ options[:start_paused] = true
24
+ end
25
+ end
26
+
27
+ parser.parse!
28
+ parser.abort(parser.help) if ARGV.shift != "run"
29
+ parser.abort(parser.help) if ARGV.empty?
30
+
31
+ env = {}
32
+ options.each do |k, v|
33
+ env["VERNIER_#{k.to_s.upcase}"] = v.to_s
34
+ end
35
+ vernier_path = File.expand_path('../lib', __dir__)
36
+ env['RUBYOPT'] = "-I #{vernier_path} -r vernier/autorun #{ENV['RUBYOPT']}"
37
+
38
+ Kernel.exec(env, *ARGV)