vernier 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -8
- data/ext/vernier/vernier.cc +13 -7
- data/lib/vernier/output/firefox.rb +4 -6
- data/lib/vernier/version.rb +1 -1
- data/lib/vernier.rb +3 -3
- data/vernier.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6050bca74116d0e90f98025fe23d7fbd40c6107c085e3f768d606d4f418ebc60
|
4
|
+
data.tar.gz: e302542d8b06852d28d0ec1e2528f23bba46d5ef9ea9a828c9dbcdb985a292a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d20e5f9d9c894a253bc4aeb6b9da6cb35d916e881abedf996ce19757a9cd92efe43bcc76fda0aa4ce5e334be36582adf7c716a998c4c5e1f403dc57364fb5ab
|
7
|
+
data.tar.gz: 7cf03df7bcb4f961b5b456eb781fd5818de7e18501baa01592ce17528f5eae7b272e90dcff200f861495ebb1a83c87f9146306db66ce20a9d56467ab87bce3c6
|
data/README.md
CHANGED
@@ -1,6 +1,22 @@
|
|
1
1
|
# Vernier
|
2
2
|
|
3
|
-
|
3
|
+
Next-generation Ruby sampling profiler. Tracks multiple threads, GVL activity, GC pauses, idle time, and more.
|
4
|
+
|
5
|
+
## Examples
|
6
|
+
|
7
|
+
[Livestreamed demo: Pairin' with Aaron (YouTube)](https://www.youtube.com/watch?v=9nvX3OHykGQ#t=27m43)
|
8
|
+
|
9
|
+
Sidekiq jobs from Mastodon (time, threded)
|
10
|
+
: https://share.firefox.dev/44jZRf3
|
11
|
+
|
12
|
+
Puma web requests from Mastodon (time, threded)
|
13
|
+
: https://share.firefox.dev/48FOTnF
|
14
|
+
|
15
|
+
Rails benchmark - lobste.rs (time)
|
16
|
+
: https://share.firefox.dev/3Ld89id
|
17
|
+
|
18
|
+
`require "irb"` (retained memory)
|
19
|
+
: https://share.firefox.dev/3DhLsFa
|
4
20
|
|
5
21
|
## Installation
|
6
22
|
|
@@ -10,24 +26,24 @@ gem 'vernier'
|
|
10
26
|
|
11
27
|
## Usage
|
12
28
|
|
13
|
-
### Retained memory
|
14
29
|
|
15
|
-
|
30
|
+
### Time
|
16
31
|
|
17
32
|
```
|
18
|
-
|
33
|
+
Vernier.trace(out: "time_profile.json") { some_slow_method }
|
19
34
|
```
|
20
35
|
|
21
|
-
The output can then be viewed in the
|
36
|
+
The output can then be viewed in the Firefox Profiler (demo) or the [`profile-viewer` gem](https://github.com/tenderlove/profiler/tree/ruby) (a Ruby-customized version of the firefox profiler.
|
22
37
|
|
23
|
-
|
38
|
+
### Retained memory
|
24
39
|
|
25
|
-
|
40
|
+
Record a flamegraph of all **retained** allocations from loading `irb`.
|
26
41
|
|
27
42
|
```
|
28
|
-
Vernier.
|
43
|
+
ruby -r vernier -e 'Vernier.trace_retained(out: "irb_profile.json") { require "irb" }'
|
29
44
|
```
|
30
45
|
|
46
|
+
|
31
47
|
## Development
|
32
48
|
|
33
49
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/ext/vernier/vernier.cc
CHANGED
@@ -72,13 +72,17 @@ class TimeStamp {
|
|
72
72
|
return TimeStamp(0);
|
73
73
|
}
|
74
74
|
|
75
|
-
|
76
|
-
|
75
|
+
// SleepUntil a specified timestamp
|
76
|
+
// Highly accurate manual sleep time
|
77
|
+
static void SleepUntil(const TimeStamp &target_time) {
|
78
|
+
if (target_time.zero()) return;
|
79
|
+
struct timespec ts = target_time.timespec();
|
77
80
|
|
78
81
|
int res;
|
79
82
|
do {
|
80
|
-
|
81
|
-
|
83
|
+
// do nothing until it's time :)
|
84
|
+
sleep(0);
|
85
|
+
} while (target_time > TimeStamp::Now());
|
82
86
|
}
|
83
87
|
|
84
88
|
static TimeStamp from_microseconds(uint64_t us) {
|
@@ -1091,6 +1095,9 @@ class RetainedCollector : public BaseCollector {
|
|
1091
1095
|
VALUE weights = rb_ary_new();
|
1092
1096
|
rb_hash_aset(thread_hash, sym("weights"), weights);
|
1093
1097
|
|
1098
|
+
rb_hash_aset(thread_hash, sym("name"), rb_str_new_cstr("retained memory"));
|
1099
|
+
rb_hash_aset(thread_hash, sym("started_at"), ULL2NUM(collector->started_at.nanoseconds()));
|
1100
|
+
|
1094
1101
|
for (auto& obj: collector->object_list) {
|
1095
1102
|
const auto search = collector->object_frames.find(obj);
|
1096
1103
|
if (search != collector->object_frames.end()) {
|
@@ -1252,13 +1259,12 @@ class TimeCollector : public BaseCollector {
|
|
1252
1259
|
|
1253
1260
|
next_sample_schedule += interval;
|
1254
1261
|
|
1262
|
+
// If sampling falls behind, restart, and check in another interval
|
1255
1263
|
if (next_sample_schedule < sample_complete) {
|
1256
|
-
//fprintf(stderr, "fell behind by %ius\n", (sample_complete - next_sample_schedule).microseconds());
|
1257
1264
|
next_sample_schedule = sample_complete + interval;
|
1258
1265
|
}
|
1259
1266
|
|
1260
|
-
TimeStamp
|
1261
|
-
TimeStamp::Sleep(sleep_time);
|
1267
|
+
TimeStamp::SleepUntil(next_sample_schedule);
|
1262
1268
|
}
|
1263
1269
|
|
1264
1270
|
thread_stopped.post();
|
@@ -157,14 +157,15 @@ module Vernier
|
|
157
157
|
class Thread
|
158
158
|
attr_reader :profile
|
159
159
|
|
160
|
-
def initialize(profile, categorizer, name:, tid:, samples:, weights:, timestamps
|
160
|
+
def initialize(profile, categorizer, name:, tid:, samples:, weights:, timestamps: nil, sample_categories: nil, markers:, started_at:, stopped_at: nil)
|
161
161
|
@profile = profile
|
162
162
|
@categorizer = categorizer
|
163
163
|
@tid = tid
|
164
164
|
@name = name
|
165
165
|
|
166
|
+
timestamps ||= [0] * samples.size
|
166
167
|
@samples, @weights, @timestamps = samples, weights, timestamps
|
167
|
-
@sample_categories = sample_categories
|
168
|
+
@sample_categories = sample_categories || ([0] * samples.size)
|
168
169
|
@markers = markers
|
169
170
|
|
170
171
|
@started_at, @stopped_at = started_at, stopped_at
|
@@ -211,7 +212,7 @@ module Vernier
|
|
211
212
|
def data
|
212
213
|
{
|
213
214
|
name: @name,
|
214
|
-
isMainThread: @tid == ::Thread.main.native_thread_id,
|
215
|
+
isMainThread: (@tid == ::Thread.main.native_thread_id) || (profile.threads.size == 1),
|
215
216
|
processStartupTime: 0, # FIXME
|
216
217
|
processShutdownTime: nil, # FIXME
|
217
218
|
registerTime: (@started_at - 0) / 1_000_000.0,
|
@@ -237,8 +238,6 @@ module Vernier
|
|
237
238
|
end
|
238
239
|
|
239
240
|
def markers_table
|
240
|
-
size = @markers.size
|
241
|
-
|
242
241
|
string_indexes = []
|
243
242
|
start_times = []
|
244
243
|
end_times = []
|
@@ -292,7 +291,6 @@ module Vernier
|
|
292
291
|
times = (0...size).to_a
|
293
292
|
end
|
294
293
|
|
295
|
-
raise unless samples.size == size
|
296
294
|
raise unless weights.size == size
|
297
295
|
raise unless times.size == size
|
298
296
|
|
data/lib/vernier/version.rb
CHANGED
data/lib/vernier.rb
CHANGED
@@ -19,11 +19,11 @@ module Vernier
|
|
19
19
|
yield collector
|
20
20
|
ensure
|
21
21
|
result = collector.stop
|
22
|
+
if out
|
23
|
+
File.write(out, Output::Firefox.new(result).output)
|
24
|
+
end
|
22
25
|
end
|
23
26
|
|
24
|
-
if out
|
25
|
-
File.write(out, Output::Firefox.new(result).output)
|
26
|
-
end
|
27
27
|
result
|
28
28
|
end
|
29
29
|
|
data/vernier.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = spec.summary
|
13
13
|
spec.homepage = "https://github.com/jhawthorn/vernier"
|
14
14
|
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = ">= 3.2.
|
15
|
+
spec.required_ruby_version = ">= 3.2.1"
|
16
16
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
18
18
|
spec.metadata["source_code_uri"] = spec.homepage
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vernier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Hawthorn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: An experimental profiler
|
14
14
|
email:
|
@@ -60,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
60
60
|
requirements:
|
61
61
|
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: 3.2.
|
63
|
+
version: 3.2.1
|
64
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|