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 +4 -4
- data/README.md +2 -2
- data/bin/vernier +4 -0
- data/examples/minitest.rb +20 -0
- data/examples/ractor.rb +11 -0
- data/examples/rails.rb +125 -0
- data/exe/vernier +38 -0
- data/ext/vernier/vernier.cc +558 -295
- data/lib/vernier/autorun.rb +65 -0
- data/lib/vernier/collector.rb +47 -28
- data/lib/vernier/marker.rb +11 -11
- data/lib/vernier/output/firefox.rb +74 -41
- data/lib/vernier/result.rb +139 -0
- data/lib/vernier/version.rb +1 -1
- data/lib/vernier.rb +3 -130
- metadata +11 -4
- data/sig/vernier.rbs +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52f738e495accaaab1af3f33a806a7b20467aa8f2a93f4b7bf8d7300fdaf88ad
|
4
|
+
data.tar.gz: e6877e7315fb990e8db9482b940a96068770987989fec85a804c75ce79b62022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|

|
24
24
|
|
data/bin/vernier
ADDED
@@ -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
|
data/examples/ractor.rb
ADDED
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)
|