stackprof 0.2.22 → 0.2.24

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e473c6b4408f04dc69f4abd425ab68896b4f705adadd467ded771003eb84da1
4
- data.tar.gz: 5bfaa3c22d7e59271f65136b0237cddc4d1a97edf9650db4caf53c9b36fda55e
3
+ metadata.gz: 90e33127951d53147b6a65704446ec812999df9525d868865029ee1c7450445d
4
+ data.tar.gz: 19a5f104482f355cb1957b71b18b15b9ca9bb981cfcc109688366e53704c5711
5
5
  SHA512:
6
- metadata.gz: eb0ffc8bac6c1c66b13ce67d89bac3fbd1c601754024c3e8455e194a35e58f3c515586aa0ffeee4e30985a6e140ce64724c0960dce8de67d8a3e0f0e912d3898
7
- data.tar.gz: 4cfc9aa211ab10a7b0a0c222e94538311bd91950fa32fc0602e2535468df4c48158219cad2f2f6fee015f94a9b415c3a285406fcc66ab27676a6572492b2d7f9
6
+ metadata.gz: 17610238200852f97afcc730efd9171c46c3a001ff7d5b82cb65fc92f96d9d2b206474bcecc7eeee1981365d2a07fd4dad460edc54a8bc9c8b1e6c7412f7cde3
7
+ data.tar.gz: 35cc1394b526edd0782468b06d54f66eb1ff10e5741becf486f68f0b141511fad9db622816004a4ae2e1a59cff048abe2d5697848eff127640663e9246f33cca
data/bin/stackprof CHANGED
@@ -2,31 +2,33 @@
2
2
  require 'optparse'
3
3
  require 'stackprof'
4
4
 
5
+ banner = <<-END
6
+ Usage: stackprof run [--mode=MODE|--out=FILE|--interval=INTERVAL|--format=FORMAT] -- COMMAND
7
+ Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]
8
+ END
9
+
5
10
  if ARGV.first == "run"
6
11
  ARGV.shift
7
12
  env = {}
8
- parser = OptionParser.new(ARGV) do |o|
9
- o.banner = "Usage: stackprof run [--mode|--out|--interval] -- COMMAND"
10
- o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
11
-
12
- o.on('--mode', 'Mode of sampling: cpu, wall, object, default to wall') do |mode|
13
+ parser = OptionParser.new(banner) do |o|
14
+ o.on('--mode [MODE]', String, 'Mode of sampling: cpu, wall, object, default to wall') do |mode|
13
15
  env["STACKPROF_MODE"] = mode
14
16
  end
15
17
 
16
- o.on('--out', 'The target file, which will be overwritten. Defaults to a random temporary file') do |out|
18
+ o.on('--out [FILENAME]', String, 'The target file, which will be overwritten. Defaults to a random temporary file') do |out|
17
19
  env['STACKPROF_OUT'] = out
18
20
  end
19
21
 
20
- o.on('--interval', 'Mode-relative sample rate') do |interval|
21
- env['STACKPROF_INTERVAL'] = Integer(interval).to_s
22
+ o.on('--interval [MILLISECONDS]', Integer, 'Mode-relative sample rate') do |interval|
23
+ env['STACKPROF_INTERVAL'] = interval.to_s
22
24
  end
23
25
 
24
- o.on('--raw', 'collects the extra data required by the --flamegraph and --stackcollapse report types') do
25
- env['STACKPROF_RAW'] = '1'
26
+ o.on('--raw', 'collects the extra data required by the --flamegraph and --stackcollapse report types') do |raw|
27
+ env['STACKPROF_RAW'] = raw.to_s
26
28
  end
27
29
 
28
- o.on('--ignore-gc', 'Ignore garbage collection frames') do
29
- env['STACKPROF_IGNORE_GC'] = '1'
30
+ o.on('--ignore-gc', 'Ignore garbage collection frames') do |gc|
31
+ env['STACKPROF_IGNORE_GC'] = gc.to_s
30
32
  end
31
33
  end
32
34
  parser.parse!
@@ -37,10 +39,7 @@ if ARGV.first == "run"
37
39
  else
38
40
  options = {}
39
41
 
40
- parser = OptionParser.new(ARGV) do |o|
41
- o.banner = "Usage: stackprof run [--mode|--out|--interval] -- COMMAND"
42
- o.banner = "Usage: stackprof [file.dump]+ [--text|--method=NAME|--callgrind|--graphviz]"
43
-
42
+ parser = OptionParser.new(banner) do |o|
44
43
  o.on('--text', 'Text summary per method (default)'){ options[:format] = :text }
45
44
  o.on('--json', 'JSON output (use with web viewers)'){ options[:format] = :json }
46
45
  o.on('--files', 'List of files'){ |f| options[:format] = :files }
@@ -12,6 +12,7 @@
12
12
  #include <ruby/st.h>
13
13
  #include <ruby/io.h>
14
14
  #include <ruby/intern.h>
15
+ #include <ruby/vm.h>
15
16
  #include <signal.h>
16
17
  #include <sys/time.h>
17
18
  #include <time.h>
@@ -32,6 +33,7 @@ static const char *fake_frame_cstrs[] = {
32
33
  };
33
34
 
34
35
  static int stackprof_use_postponed_job = 1;
36
+ static int ruby_vm_running = 0;
35
37
 
36
38
  #define TOTAL_FAKE_FRAMES (sizeof(fake_frame_cstrs) / sizeof(char *))
37
39
 
@@ -125,6 +127,8 @@ static struct {
125
127
  sample_time_t buffer_time;
126
128
  VALUE frames_buffer[BUF_SIZE];
127
129
  int lines_buffer[BUF_SIZE];
130
+
131
+ pthread_t target_thread;
128
132
  } _stackprof;
129
133
 
130
134
  static VALUE sym_object, sym_wall, sym_cpu, sym_custom, sym_name, sym_file, sym_line;
@@ -219,6 +223,7 @@ stackprof_start(int argc, VALUE *argv, VALUE self)
219
223
  _stackprof.ignore_gc = ignore_gc;
220
224
  _stackprof.metadata = metadata;
221
225
  _stackprof.out = out;
226
+ _stackprof.target_thread = pthread_self();
222
227
 
223
228
  if (raw) {
224
229
  capture_timestamp(&_stackprof.last_sample_at);
@@ -721,7 +726,27 @@ stackprof_signal_handler(int sig, siginfo_t *sinfo, void *ucontext)
721
726
  _stackprof.overall_signals++;
722
727
 
723
728
  if (!_stackprof.running) return;
724
- if (!ruby_native_thread_p()) return;
729
+
730
+ // There's a possibility that the signal handler is invoked *after* the Ruby
731
+ // VM has been shut down (e.g. after ruby_cleanup(0)). In this case, things
732
+ // that rely on global VM state (e.g. rb_during_gc) will segfault.
733
+ if (!ruby_vm_running) return;
734
+
735
+ if (_stackprof.mode == sym_wall) {
736
+ // In "wall" mode, the SIGALRM signal will arrive at an arbitrary thread.
737
+ // In order to provide more useful results, especially under threaded web
738
+ // servers, we want to forward this signal to the original thread
739
+ // StackProf was started from.
740
+ // According to POSIX.1-2008 TC1 pthread_kill and pthread_self should be
741
+ // async-signal-safe.
742
+ if (pthread_self() != _stackprof.target_thread) {
743
+ pthread_kill(_stackprof.target_thread, sig);
744
+ return;
745
+ }
746
+ } else {
747
+ if (!ruby_native_thread_p()) return;
748
+ }
749
+
725
750
  if (pthread_mutex_trylock(&lock)) return;
726
751
 
727
752
  if (!_stackprof.ignore_gc && rb_during_gc()) {
@@ -827,6 +852,12 @@ stackprof_use_postponed_job_l(VALUE self)
827
852
  return Qnil;
828
853
  }
829
854
 
855
+ static void
856
+ stackprof_at_exit(ruby_vm_t* vm)
857
+ {
858
+ ruby_vm_running = 0;
859
+ }
860
+
830
861
  void
831
862
  Init_stackprof(void)
832
863
  {
@@ -837,6 +868,9 @@ Init_stackprof(void)
837
868
  */
838
869
  stackprof_use_postponed_job = RUBY_API_VERSION_MAJOR < 3;
839
870
 
871
+ ruby_vm_running = 1;
872
+ ruby_vm_at_exit(stackprof_at_exit);
873
+
840
874
  #define S(name) sym_##name = ID2SYM(rb_intern(#name));
841
875
  S(object);
842
876
  S(custom);
data/lib/stackprof.rb CHANGED
@@ -6,10 +6,15 @@ end
6
6
 
7
7
  if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?
8
8
  StackProf.use_postponed_job!
9
+ elsif RUBY_VERSION == "3.2.0"
10
+ # 3.2.0 crash is the signal is received at the wrong time.
11
+ # Fixed in https://github.com/ruby/ruby/pull/7116
12
+ # The fix is backported in 3.2.1: https://bugs.ruby-lang.org/issues/19336
13
+ StackProf.use_postponed_job!
9
14
  end
10
15
 
11
16
  module StackProf
12
- VERSION = '0.2.22'
17
+ VERSION = '0.2.24'
13
18
  end
14
19
 
15
20
  StackProf.autoload :Report, "stackprof/report.rb"
data/stackprof.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'stackprof'
3
- s.version = '0.2.22'
3
+ s.version = '0.2.24'
4
4
  s.homepage = 'http://github.com/tmm1/stackprof'
5
5
 
6
6
  s.authors = 'Aman Gupta'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackprof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.22
4
+ version: 0.2.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aman Gupta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-13 00:00:00.000000000 Z
11
+ date: 2023-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -99,9 +99,9 @@ licenses:
99
99
  - MIT
100
100
  metadata:
101
101
  bug_tracker_uri: https://github.com/tmm1/stackprof/issues
102
- changelog_uri: https://github.com/tmm1/stackprof/blob/v0.2.22/CHANGELOG.md
103
- documentation_uri: https://www.rubydoc.info/gems/stackprof/0.2.22
104
- source_code_uri: https://github.com/tmm1/stackprof/tree/v0.2.22
102
+ changelog_uri: https://github.com/tmm1/stackprof/blob/v0.2.24/CHANGELOG.md
103
+ documentation_uri: https://www.rubydoc.info/gems/stackprof/0.2.24
104
+ source_code_uri: https://github.com/tmm1/stackprof/tree/v0.2.24
105
105
  post_install_message:
106
106
  rdoc_options: []
107
107
  require_paths: