vernier 0.6.0 → 0.7.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: b9ba6d060b4eb230a865df67f378f81b08721d36a9f8cf394f9a8d5d0455b844
4
- data.tar.gz: d01c209f5fab9bc99940fb5b967a722f69c75376dd6aba0c3e7759a9c52bc698
3
+ metadata.gz: 4988794520691870cb34178385be791e28fa4806eb1f6934b0d0abf52c8a070c
4
+ data.tar.gz: b1e63c6f5398f61fb68d634f17f33dc6aa7461344cb8acf446dd75ca52395818
5
5
  SHA512:
6
- metadata.gz: 65e359b25b1cc5a5e3dc2724ec7c98eb4f20203a98e0fd8f402b5875fe329afb6a20f6fc722f8da2febdd4cd30e8e2d56a00e42a4e5262baffb7a250fba79f3d
7
- data.tar.gz: bf9ca5416e6b7b17d316eb9c762273ab711518c7ba50c862f803eed9e2d17fcbdeee378f9d6702d4029715926d105398105c5eb0f6aec046fa540611993ec89a
6
+ metadata.gz: '082561b2a381f88c540e607d1dd9c0d42d841a0de82fc61471fb2d67754ee14a4fd1e87fa71896b586077664e61fd1db623fd250cd13064d198c9dc91d3f13ed'
7
+ data.tar.gz: a28c197d405e4f52d999db3ae73187047886e1fcfb7d353d13f26ad5ba4b61f0675daf617119b37d72ad3760bd0dffcae234f2dcb0a0e960a60046dfb87dd784
data/Gemfile CHANGED
@@ -8,5 +8,6 @@ gemspec
8
8
  gem "rake", "~> 13.0"
9
9
 
10
10
  gem "rake-compiler"
11
+ gem "benchmark-ips"
11
12
 
12
13
  gem "minitest", "~> 5.0"
data/README.md CHANGED
@@ -30,17 +30,33 @@ gem 'vernier'
30
30
 
31
31
  ## Usage
32
32
 
33
+ The output can be viewed in the web app at https://vernier.prof or locally using the [`profile-viewer` gem](https://github.com/tenderlove/profiler/tree/ruby) (both are lightly customized versions of the firefox profiler frontend, which profiles are also compatible with).
34
+
35
+ - **Flame Graph**: Shows proportionally how much time is spent within particular stack frames. Frames are grouped together, which means that x-axis / left-to-right order is not meaningful.
36
+ - **Stack Chart**: Shows the stack at each sample with the x-axis representing time and can be read left-to-right.
37
+
33
38
 
34
39
  ### Time
35
40
 
41
+
42
+ #### Command line
43
+
44
+ The easiest way to record a program or script is via the CLI
45
+
36
46
  ```
37
- Vernier.trace(out: "time_profile.json") { some_slow_method }
47
+ $ vernier run -- ruby -e 'sleep 1'
48
+ starting profiler with interval 500
49
+ #<Vernier::Result 1.001589 seconds, 1 threads, 2002 samples, 1 unique>
50
+ written to /tmp/profile20240328-82441-gkzffc.vernier.json
38
51
  ```
39
52
 
40
- The output can be viewed in the web app at https://vernier.prof or locally using the [`profile-viewer` gem](https://github.com/tenderlove/profiler/tree/ruby) (both are lightly customized versions of the firefox profiler frontend, which profiles are also compatible with).
53
+ ### Block of code
41
54
 
42
- - **Flame Graph**: Shows proportionally how much time is spent within particular stack frames. Frames are grouped together, which means that x-axis / left-to-right order is not meaningful.
43
- - **Stack Chart**: Shows the stack at each sample with the x-axis representing time and can be read left-to-right.
55
+ ``` ruby
56
+ Vernier.run(out: "time_profile.json") do
57
+ some_slow_method
58
+ end
59
+ ```
44
60
 
45
61
  ### Retained memory
46
62
 
@@ -0,0 +1,62 @@
1
+ # Different (bad) ways to sleep
2
+
3
+ File.write("#{__dir__}/my_sleep.c", <<~EOF)
4
+ #include <time.h>
5
+ #include <sys/errno.h>
6
+
7
+ void my_sleep() {
8
+ struct timespec ts;
9
+ ts.tv_sec = 1;
10
+ ts.tv_nsec = 0;
11
+
12
+ int rc;
13
+ do {
14
+ rc = nanosleep(&ts, &ts);
15
+ } while (rc < 0 && errno == EINTR);
16
+ }
17
+ EOF
18
+
19
+ soext = RbConfig::CONFIG["SOEXT"]
20
+ system("gcc", "-shared", "-fPIC", "#{__dir__}/my_sleep.c", "-o", "#{__dir__}/my_sleep.#{soext}")
21
+
22
+ require "fiddle"
23
+
24
+ SLEEP_LIB = Fiddle.dlopen("./my_sleep.#{soext}")
25
+
26
+ def cfunc_sleep_gvl
27
+ Fiddle::Function.new(SLEEP_LIB['my_sleep'], [], Fiddle::TYPE_VOID, need_gvl: true).call
28
+ end
29
+
30
+ def cfunc_sleep_idle
31
+ Fiddle::Function.new(SLEEP_LIB['my_sleep'], [], Fiddle::TYPE_VOID, need_gvl: true).call
32
+ end
33
+
34
+ def ruby_sleep_gvl
35
+ target = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) + 1000
36
+ while Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) < target
37
+ i = 0
38
+ while i < 1000
39
+ i += 1
40
+ end
41
+ end
42
+ end
43
+
44
+ def sleep_idle
45
+ sleep 1
46
+ end
47
+
48
+ def run(name)
49
+ STDOUT.print "#{name}..."
50
+ STDOUT.flush
51
+
52
+ before = Process.clock_gettime(Process::CLOCK_MONOTONIC)
53
+ send(name)
54
+ after = Process.clock_gettime(Process::CLOCK_MONOTONIC)
55
+
56
+ STDOUT.puts " %.2fs" % (after - before)
57
+ end
58
+
59
+ run(:cfunc_sleep_gvl)
60
+ run(:cfunc_sleep_idle)
61
+ run(:ruby_sleep_gvl)
62
+ run(:sleep_idle)
@@ -0,0 +1,39 @@
1
+ require "benchmark/ips"
2
+ require "vernier"
3
+
4
+ def compare(**options, &block)
5
+ block.call
6
+
7
+ Benchmark.ips do |x|
8
+ x.report "no profiler" do |n|
9
+ n.times do
10
+ block.call
11
+ end
12
+ end
13
+
14
+ x.report "vernier" do |n|
15
+ Vernier.profile(**options) do
16
+ n.times do
17
+ block.call
18
+ end
19
+ end
20
+ end
21
+
22
+ x.compare!
23
+ end
24
+ end
25
+
26
+ compare do
27
+ i = 0
28
+ while i < 10_000
29
+ i += 1
30
+ end
31
+ end
32
+
33
+ compare(allocation_sample_rate: 1000) do
34
+ Object.new
35
+ end
36
+
37
+ compare(allocation_sample_rate: 1) do
38
+ Object.new
39
+ end