rbtrace 0.4.14 → 0.5.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/.github/workflows/ci.yml +26 -0
- data/CHANGELOG +7 -0
- data/ext/extconf.rb +0 -5
- data/ext/rbtrace.c +12 -20
- data/lib/rbtrace/cli.rb +44 -3
- data/lib/rbtrace/core_ext.rb +0 -4
- data/lib/rbtrace/msgq.rb +2 -1
- data/lib/rbtrace/rbtracer.rb +3 -1
- data/lib/rbtrace/version.rb +1 -1
- data/lib/rbtrace.rb +22 -0
- data/rbtrace.gemspec +1 -1
- data/server.rb +1 -1
- data/test.sh +6 -4
- metadata +10 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dc6fc7320951955050f41babf4a1effbec1eaac42e9103a0c8b08c69cc2ad090
|
|
4
|
+
data.tar.gz: 105f410c0c78e6f23c3d6617165b7a1c3c9a72976735cfd185481c91acb3bb17
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
-
|
|
1148
|
+
rb_const_set(rbtrace_module, rb_intern("BUF_SIZE"), INT2NUM(BUF_SIZE));
|
|
1145
1149
|
|
|
1146
|
-
|
|
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(
|
|
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}"
|
data/lib/rbtrace/core_ext.rb
CHANGED
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 =
|
|
9
|
+
BUF_SIZE = RBTrace::BUF_SIZE
|
|
9
10
|
IPC_NOWAIT = 004000
|
|
10
11
|
|
|
11
12
|
layout :mtype, :long,
|
data/lib/rbtrace/rbtracer.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
data/lib/rbtrace/version.rb
CHANGED
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"
|
|
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
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
|
+
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:
|
|
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: '
|
|
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: '
|
|
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.
|
|
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'
|