rbtrace 0.4.14 → 0.5.0

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: 78fc8aa96b3b20a4663ceaef1253f41443689e85f344a9efecb60c240e85183b
4
- data.tar.gz: 2f2ab561dfe12096dcbe28ff188d07e34af48bbed936f09bbc0dd23309132bea
3
+ metadata.gz: dc6fc7320951955050f41babf4a1effbec1eaac42e9103a0c8b08c69cc2ad090
4
+ data.tar.gz: 105f410c0c78e6f23c3d6617165b7a1c3c9a72976735cfd185481c91acb3bb17
5
5
  SHA512:
6
- metadata.gz: 1710793189ea23b9048c68ff61c1c7f52202b4e7770991e4c049f9b1b069dbbe4fd71f59e2e79a06d34c4c15628073d0498175fcbb64572152c22b9636557a09
7
- data.tar.gz: 315c8c2bc040cf790e4964a93ee9f50b97f9b2b7718f71790e8af36cb2d1fe01d529da06fd6b346747e45fc82b52b2fde6fd62bf9053010e8e93d38f76e575fe
6
+ metadata.gz: a4e42ec27236d32067f52fa3c0ed1a1a3eb518f1f0d4de9c42dcbec787dc62346f39c790ae2b74fcca6835bc1413c3e44216398c8ca46d74d760f0d75a551873
7
+ data.tar.gz: 4602057b9797b58337d2308a195ee1d1e6e9247a7e08bebf40d153bd9c6f4fb1f4871851b514b0fef471cf87df002632b0c75ff6511dc926e58c86be453d8b67
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: Test
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ ruby:
7
+ name: Ruby ${{ matrix.ruby }}
8
+ timeout-minutes: 15
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ os: ["ubuntu-latest"]
13
+ ruby: ["3.2", "3.1", "3.0", "2.7", "2.6"]
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - name: Check out code
17
+ uses: actions/checkout@v3
18
+
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ bundler-cache: true
24
+
25
+ - name: Tests
26
+ run: ./test.sh
data/CHANGELOG ADDED
@@ -0,0 +1,7 @@
1
+ - 0.5.0 - 02-12-2023
2
+
3
+ - Improved --backtraces implementation
4
+ - Added --shapedump which is useful for lighter weight object shape dumps on Ruby 3.2 and up
5
+ - Move heap dumping to a fork for better performance
6
+ - Use TypedData API which has been supported for a very long time
7
+ - Update CI and fix some small errors
data/ext/extconf.rb CHANGED
@@ -63,11 +63,6 @@ have_func('rb_during_gc', 'ruby.h')
63
63
  have_func('rb_gc_add_event_hook', ['ruby.h', 'node.h'])
64
64
  have_func('rb_postponed_job_register_one', 'ruby.h')
65
65
 
66
- # increase message size on linux
67
- if RUBY_PLATFORM =~ /linux/
68
- $defs.push("-DBUF_SIZE=256")
69
- end
70
-
71
66
  # warnings save lives
72
67
  $CFLAGS << " -Wall "
73
68
 
data/ext/rbtrace.c CHANGED
@@ -79,7 +79,7 @@ timeofday_usec()
79
79
  #define MAX_TRACERS 100 // max method tracers
80
80
  #define MAX_EXPRS 10 // max expressions per tracer
81
81
  #ifndef BUF_SIZE // msgq buffer size
82
- #define BUF_SIZE 120
82
+ #define BUF_SIZE 1024
83
83
  #endif
84
84
 
85
85
  typedef struct {
@@ -876,9 +876,7 @@ eval_inspect(VALUE rb_code) {
876
876
  }
877
877
 
878
878
  static VALUE
879
- rescue_inspect(VALUE arg) {
880
- VALUE exception = rb_errinfo(); /* get last exception */
881
- rb_set_errinfo(Qnil);
879
+ rescue_inspect(VALUE arg, VALUE exception) {
882
880
  return rb_funcall(exception, rb_intern("inspect"), 0);
883
881
  }
884
882
 
@@ -891,7 +889,6 @@ rbtrace__process_event(msgpack_object cmd)
891
889
  static int last_tracer_id = -1; // hax
892
890
  char query[BUF_SIZE];
893
891
 
894
- char code[BUF_SIZE+150];
895
892
  VALUE val = Qnil;
896
893
 
897
894
  msgpack_object_array ary;
@@ -1135,31 +1132,26 @@ send_write(VALUE klass, VALUE val) {
1135
1132
  return Qnil;
1136
1133
  }
1137
1134
 
1135
+ static const rb_data_type_t rbtrace_type = {
1136
+ "RBTrace",
1137
+ {
1138
+ rbtrace_gc_mark,
1139
+ }
1140
+ };
1141
+
1138
1142
  void
1139
1143
  Init_rbtrace()
1140
1144
  {
1141
1145
  rbtrace_module = rb_define_module("RBTrace");
1142
1146
  VALUE output = rb_define_module_under(rbtrace_module, "OUT");
1143
1147
 
1144
- rb_define_singleton_method(output, "write", send_write, 1);
1148
+ rb_const_set(rbtrace_module, rb_intern("BUF_SIZE"), INT2NUM(BUF_SIZE));
1145
1149
 
1146
- rb_eval_string(
1147
- "module RBTrace\n"
1148
- " def self.eval_context\n"
1149
- " @eval_context ||= binding\n"
1150
- " end\n"
1151
-
1152
- " def self.eval_and_inspect(code)\n"
1153
- " t = Thread.new { Thread.current[:output] = eval_context.eval(code).inspect }\n"
1154
- " t.join\n"
1155
- " t[:output]\n"
1156
- " end\n"
1157
- "end\n"
1158
- );
1150
+ rb_define_singleton_method(output, "write", send_write, 1);
1159
1151
 
1160
1152
  // hook into the gc
1161
- gc_hook = Data_Wrap_Struct(rb_cObject, rbtrace_gc_mark, NULL, NULL);
1162
1153
  rb_global_variable(&gc_hook);
1154
+ gc_hook = TypedData_Wrap_Struct(rb_cObject, &rbtrace_type, NULL);
1163
1155
 
1164
1156
  // catch signal telling us to read from the msgq
1165
1157
  #if defined(HAVE_RB_POSTPONED_JOB_REGISTER_ONE)
data/lib/rbtrace/cli.rb CHANGED
@@ -225,6 +225,9 @@ EOS
225
225
  :default => "AUTO",
226
226
  :short => "-h"
227
227
 
228
+ opt :shapesdump,
229
+ "generate a shapes dump for the process in FILENAME",
230
+ :default => "AUTO"
228
231
  end
229
232
 
230
233
  opts = Optimist.with_standard_exception_handling(parser) do
@@ -241,7 +244,7 @@ EOS
241
244
  end
242
245
 
243
246
  unless %w[ fork eval interactive backtrace backtraces slow slowcpu firehose methods config gc memory heapdump].find{ |n| opts[:"#{n}_given"] }
244
- $stderr.puts "Error: --slow, --slowcpu, --gc, --firehose, --methods, --interactive, --backtraces, --backtrace, --memory, --heapdump or --config required."
247
+ $stderr.puts "Error: --slow, --slowcpu, --gc, --firehose, --methods, --interactive, --backtraces, --backtrace, --memory, --heapdump, --shapesdump or --config required."
245
248
  $stderr.puts "Try --help for help."
246
249
  exit(-1)
247
250
  end
@@ -449,7 +452,7 @@ EOS
449
452
 
450
453
  delim = "146621c9d681409aa"
451
454
 
452
- code = "Thread.list.map{|t| t.backtrace[0...#{num}].join(\"#{delim}\")}.join(\"#{delim*2}\")"
455
+ code = "Thread.list.reject { |t| t.name == '__RBTrace__' }.map{ |t| t.backtrace[0...#{num}].join(\"#{delim}\")}.join(\"#{delim*2}\")"
453
456
 
454
457
  if res = tracer.eval(code)
455
458
  tracer.puts res.split(delim).join("\n")
@@ -499,9 +502,47 @@ EOS
499
502
  temp.unlink
500
503
  end
501
504
 
502
- tracer.eval("file = File.open('#{filename}', 'w'); ObjectSpace.dump_all(output: file); file.close")
505
+ tracer.eval(<<-RUBY)
506
+ Thread.new do
507
+ Thread.current.name = '__RBTrace__'
508
+ pid = ::Process.fork do
509
+ file = File.open('#{filename}.tmp', 'w')
510
+ ObjectSpace.dump_all(output: file)
511
+ file.close
512
+ File.rename('#{filename}.tmp', '#{filename}')
513
+ exit!(0)
514
+ end
515
+ Process.waitpid(pid)
516
+ end
517
+ RUBY
503
518
  puts "Heapdump being written to #{filename}"
504
519
 
520
+ elsif opts[:shapesdump_given]
521
+ filename = opts[:shapesdump]
522
+
523
+ if filename == "AUTO"
524
+ require 'tempfile'
525
+ temp = Tempfile.new("dump")
526
+ filename = temp.path
527
+ temp.close
528
+ temp.unlink
529
+ end
530
+
531
+ tracer.eval(<<-RUBY)
532
+ Thread.new do
533
+ Thread.current.name = '__RBTrace__'
534
+ pid = ::Process.fork do
535
+ file = File.open('#{filename}.tmp', 'w')
536
+ ObjectSpace.dump_shapes(output: file)
537
+ file.close
538
+ File.rename('#{filename}.tmp', '#{filename}')
539
+ exit!(0)
540
+ end
541
+ Process.waitpid(pid)
542
+ end
543
+ RUBY
544
+ puts "Shapes dump being written to #{filename}"
545
+
505
546
  elsif opts[:eval_given]
506
547
  if res = tracer.eval(code = opts[:eval])
507
548
  tracer.puts ">> #{code}"
@@ -1,7 +1,3 @@
1
- class String
2
- alias :bytesize :size
3
- end unless ''.respond_to?(:bytesize)
4
-
5
1
  module FFI::LastError
6
2
  Errnos = Errno::constants.map(&Errno.method(:const_get)).inject({}) do |hash, c|
7
3
  hash[ c.const_get(:Errno) ] = c
data/lib/rbtrace/msgq.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'rbtrace'
1
2
  require 'ffi'
2
3
 
3
4
  module MsgQ
@@ -5,7 +6,7 @@ module MsgQ
5
6
  ffi_lib FFI::CURRENT_PROCESS
6
7
 
7
8
  class EventMsg < FFI::Struct
8
- BUF_SIZE = RUBY_PLATFORM =~ /linux/ ? 256 : 120
9
+ BUF_SIZE = RBTrace::BUF_SIZE
9
10
  IPC_NOWAIT = 004000
10
11
 
11
12
  layout :mtype, :long,
@@ -323,7 +323,9 @@ class RBTracer
323
323
  msg = cmd.to_msgpack
324
324
  # A message is null-terminated, but bytesize gives the unterminated
325
325
  # length.
326
- raise ArgumentError, 'command is too long' if msg.bytesize >= MsgQ::EventMsg::BUF_SIZE
326
+ if msg.bytesize >= RbTrace::BUF_SIZE
327
+ raise ArgumentError, "command is too long (#{msg.bytesize}B >= #{MsgQ::EventMsg::BUF_SIZE}B)"
328
+ end
327
329
  MsgQ::EventMsg.send_cmd(@qo, msg)
328
330
  rescue Errno::EINTR
329
331
  retry
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class RBTracer
4
- VERSION = '0.4.14'
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/rbtrace.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RBTrace
4
+ class << self
5
+ def eval_and_inspect(code)
6
+ t = Thread.new do
7
+ Thread.current.name = '__RBTrace__'
8
+ Thread.current[:output] = eval_context.eval(code).inspect
9
+ end
10
+ t.join
11
+ t[:output]
12
+ end
13
+
14
+ private
15
+
16
+ def eval_context
17
+ @eval_context ||= binding
18
+ end
19
+ end
20
+ end
21
+
22
+ require 'rbtrace.so'
data/rbtrace.gemspec CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency 'optimist', '>= 3.0.0'
24
24
  s.add_dependency 'msgpack', '>= 0.4.3'
25
25
 
26
- s.add_development_dependency "rake", "~> 10.0"
26
+ s.add_development_dependency "rake"
27
27
 
28
28
  s.license = "MIT"
29
29
  s.summary = 'rbtrace: like strace but for ruby code'
data/server.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'ext/rbtrace'
1
+ require 'rbtrace'
2
2
  require 'tmpdir'
3
3
 
4
4
  class String
data/test.sh CHANGED
@@ -12,7 +12,7 @@ cd ..
12
12
  bundle check
13
13
  export RUBYOPT="-I.:lib"
14
14
 
15
- ruby server.rb &
15
+ bundle exec ruby server.rb &
16
16
  export PID=$!
17
17
 
18
18
  trap cleanup INT TERM
@@ -23,11 +23,11 @@ cleanup() {
23
23
 
24
24
  trace() {
25
25
  echo ------------------------------------------
26
- echo ./bin/rbtrace -p $PID $*
26
+ echo ./bin/rbtrace -p $PID "$@"
27
27
  echo ------------------------------------------
28
- ./bin/rbtrace -p $PID $* &
28
+ bundle exec ./bin/rbtrace -p $PID "$@" &
29
29
  sleep 2
30
- kill $!
30
+ kill $! || true
31
31
  wait $! || true
32
32
  echo
33
33
  }
@@ -37,6 +37,8 @@ trace -m sleep
37
37
  trace -m sleep Dir.chdir Dir.pwd Process.pid "String#gsub" "String#*"
38
38
  trace -m "Kernel#"
39
39
  trace -m "String#gsub(self,@test)" "String#*(self,__source__)" "String#multiply_vowels(self,self.length,num)"
40
+ trace -e 'p(1 + 1)'
41
+ trace -h
40
42
  trace --gc --slow=200
41
43
  trace --gc -m Dir.
42
44
  trace --slow=250
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbtrace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.14
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aman Gupta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-03 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '0'
69
69
  description: rbtrace shows you method calls happening inside another ruby process
70
70
  in real time.
71
71
  email: aman@tmm1.net
@@ -75,7 +75,9 @@ extensions:
75
75
  - ext/extconf.rb
76
76
  extra_rdoc_files: []
77
77
  files:
78
+ - ".github/workflows/ci.yml"
78
79
  - ".gitignore"
80
+ - CHANGELOG
79
81
  - Gemfile
80
82
  - LICENSE
81
83
  - README.md
@@ -85,6 +87,7 @@ files:
85
87
  - ext/extconf.rb
86
88
  - ext/rbtrace.c
87
89
  - ext/src/msgpack-1.1.0.tar.gz
90
+ - lib/rbtrace.rb
88
91
  - lib/rbtrace/cli.rb
89
92
  - lib/rbtrace/core_ext.rb
90
93
  - lib/rbtrace/interactive/irb.rb
@@ -123,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
126
  - !ruby/object:Gem::Version
124
127
  version: '0'
125
128
  requirements: []
126
- rubygems_version: 3.0.3
129
+ rubygems_version: 3.4.19
127
130
  signing_key:
128
131
  specification_version: 4
129
132
  summary: 'rbtrace: like strace but for ruby code'