rbtrace 0.3.16 → 0.3.17
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rbtrace +13 -8
- data/ext/rbtrace.c +33 -8
- data/rbtrace.gemspec +1 -1
- data/server.rb +10 -0
- data/test.sh +17 -14
- metadata +4 -4
data/bin/rbtrace
CHANGED
@@ -202,9 +202,9 @@ class RBTracer
|
|
202
202
|
# msec - The Fixnum threshold in milliseconds
|
203
203
|
#
|
204
204
|
# Returns nothing.
|
205
|
-
def watch(msec)
|
205
|
+
def watch(msec, cpu_only=false)
|
206
206
|
@watch_slow = true
|
207
|
-
send_cmd(:watch, msec)
|
207
|
+
send_cmd(cpu_only ? :watchcpu : :watch, msec)
|
208
208
|
end
|
209
209
|
|
210
210
|
# Turn on the firehose (show all method calls).
|
@@ -658,7 +658,7 @@ class RBTracer
|
|
658
658
|
parser = Trollop::Parser.new do
|
659
659
|
version <<-EOS
|
660
660
|
rbtrace: like strace, but for ruby code
|
661
|
-
version 0.3.
|
661
|
+
version 0.3.17
|
662
662
|
(c) 2011 Aman Gupta (tmm1)
|
663
663
|
http://github.com/tmm1/rbtrace
|
664
664
|
EOS
|
@@ -736,6 +736,11 @@ EOS
|
|
736
736
|
:default => 250,
|
737
737
|
:short => '-s'
|
738
738
|
|
739
|
+
opt :slowcpu,
|
740
|
+
"watch for method calls slower than 250 milliseconds (cpu time only)",
|
741
|
+
:default => 250,
|
742
|
+
:short => nil
|
743
|
+
|
739
744
|
opt :slow_methods,
|
740
745
|
"method(s) to restrict --slow to",
|
741
746
|
:type => :strings
|
@@ -810,8 +815,8 @@ EOS
|
|
810
815
|
ARGV.clear
|
811
816
|
end
|
812
817
|
|
813
|
-
unless %w[ fork eval slow firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
|
814
|
-
$stderr.puts "Error: --slow, --gc, --firehose, --methods or --config required."
|
818
|
+
unless %w[ fork eval slow slowcpu firehose methods config gc ].find{ |n| opts[:"#{n}_given"] }
|
819
|
+
$stderr.puts "Error: --slow, --slowcpu, --gc, --firehose, --methods or --config required."
|
815
820
|
$stderr.puts "Try --help for help."
|
816
821
|
exit(-1)
|
817
822
|
end
|
@@ -875,7 +880,7 @@ EOS
|
|
875
880
|
filtered.each_with_index do |line, i|
|
876
881
|
STDERR.puts " [#{(i+1).to_s.rjust(max_len)}] #{line.strip}"
|
877
882
|
end
|
878
|
-
STDERR.puts " [0] all #{filtered.size} processes"
|
883
|
+
STDERR.puts " [#{'0'.rjust(max_len)}] all #{filtered.size} processes"
|
879
884
|
|
880
885
|
while true
|
881
886
|
STDERR.sync = true
|
@@ -1007,8 +1012,8 @@ EOS
|
|
1007
1012
|
tracer.firehose
|
1008
1013
|
else
|
1009
1014
|
tracer.add(methods) if methods.any?
|
1010
|
-
if opts[:slow_given]
|
1011
|
-
tracer.watch(opts[:slow])
|
1015
|
+
if opts[:slow_given] || opts[:slowcpu_given]
|
1016
|
+
tracer.watch(opts[:slowcpu] || opts[:slow], opts[:slowcpu_given])
|
1012
1017
|
tracer.add_slow(smethods) if smethods.any?
|
1013
1018
|
end
|
1014
1019
|
end
|
data/ext/rbtrace.c
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
#include <strings.h>
|
12
12
|
#include <sys/ipc.h>
|
13
13
|
#include <sys/msg.h>
|
14
|
+
#include <sys/resource.h>
|
14
15
|
#include <sys/time.h>
|
15
16
|
#include <sys/types.h>
|
16
17
|
#include <sys/wait.h>
|
@@ -37,12 +38,22 @@
|
|
37
38
|
#define RSTRING_LEN(str) RSTRING(str)->len
|
38
39
|
#endif
|
39
40
|
|
41
|
+
static uint64_t
|
42
|
+
ru_utime_usec()
|
43
|
+
{
|
44
|
+
struct rusage r_usage;
|
45
|
+
getrusage(RUSAGE_SELF, &r_usage);
|
46
|
+
return (uint64_t)r_usage.ru_utime.tv_sec*1e6 +
|
47
|
+
(uint64_t)r_usage.ru_utime.tv_usec;
|
48
|
+
}
|
49
|
+
|
40
50
|
static uint64_t
|
41
51
|
timeofday_usec()
|
42
52
|
{
|
43
53
|
struct timeval tv;
|
44
54
|
gettimeofday(&tv, NULL);
|
45
|
-
return (uint64_t)tv.tv_sec*1e6 +
|
55
|
+
return (uint64_t)tv.tv_sec*1e6 +
|
56
|
+
(uint64_t)tv.tv_usec;
|
46
57
|
}
|
47
58
|
|
48
59
|
#define MAX_CALLS 32768 // up to this many stack frames examined in slow watch mode
|
@@ -87,7 +98,9 @@ static struct {
|
|
87
98
|
bool firehose;
|
88
99
|
|
89
100
|
bool slow;
|
101
|
+
bool slowcpu;
|
90
102
|
uint64_t call_times[MAX_CALLS];
|
103
|
+
uint64_t call_utimes[MAX_CALLS];
|
91
104
|
int num_calls;
|
92
105
|
uint32_t threshold;
|
93
106
|
|
@@ -116,6 +129,7 @@ rbtracer = {
|
|
116
129
|
.firehose = false,
|
117
130
|
|
118
131
|
.slow = false,
|
132
|
+
.slowcpu = false,
|
119
133
|
.num_calls = 0,
|
120
134
|
.threshold = 250,
|
121
135
|
|
@@ -377,13 +391,18 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
377
391
|
|
378
392
|
// are we watching for slow method calls?
|
379
393
|
if (rbtracer.slow && (!tracer || tracer->is_slow)) {
|
380
|
-
uint64_t usec = timeofday_usec(),
|
394
|
+
uint64_t usec = timeofday_usec(),
|
395
|
+
ut_usec = ru_utime_usec(),
|
396
|
+
diff = 0;
|
381
397
|
|
382
398
|
switch (event) {
|
383
399
|
case RUBY_EVENT_C_CALL:
|
384
400
|
case RUBY_EVENT_CALL:
|
385
|
-
if (rbtracer.num_calls < MAX_CALLS)
|
401
|
+
if (rbtracer.num_calls < MAX_CALLS) {
|
386
402
|
rbtracer.call_times[ rbtracer.num_calls ] = usec;
|
403
|
+
if (rbtracer.slowcpu)
|
404
|
+
rbtracer.call_utimes[ rbtracer.num_calls ] = ut_usec;
|
405
|
+
}
|
387
406
|
|
388
407
|
rbtracer.num_calls++;
|
389
408
|
break;
|
@@ -393,8 +412,12 @@ event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
|
|
393
412
|
if (rbtracer.num_calls > 0) {
|
394
413
|
rbtracer.num_calls--;
|
395
414
|
|
396
|
-
if (rbtracer.num_calls < MAX_CALLS)
|
397
|
-
|
415
|
+
if (rbtracer.num_calls < MAX_CALLS) {
|
416
|
+
if (rbtracer.slowcpu)
|
417
|
+
diff = ut_usec - rbtracer.call_utimes[ rbtracer.num_calls ];
|
418
|
+
else
|
419
|
+
diff = usec - rbtracer.call_times[ rbtracer.num_calls ];
|
420
|
+
}
|
398
421
|
}
|
399
422
|
break;
|
400
423
|
}
|
@@ -568,6 +591,7 @@ rbtracer_detach()
|
|
568
591
|
|
569
592
|
rbtracer.firehose = false;
|
570
593
|
rbtracer.slow = false;
|
594
|
+
rbtracer.slowcpu = false;
|
571
595
|
rbtracer.gc = false;
|
572
596
|
rbtracer.devmode = false;
|
573
597
|
|
@@ -724,13 +748,14 @@ out:
|
|
724
748
|
}
|
725
749
|
|
726
750
|
static void
|
727
|
-
rbtracer_watch(uint32_t threshold)
|
751
|
+
rbtracer_watch(uint32_t threshold, bool cpu_time)
|
728
752
|
{
|
729
753
|
if (!rbtracer.slow) {
|
730
754
|
rbtracer.num_calls = 0;
|
731
755
|
rbtracer.threshold = threshold;
|
732
756
|
rbtracer.firehose = false;
|
733
757
|
rbtracer.slow = true;
|
758
|
+
rbtracer.slowcpu = cpu_time;
|
734
759
|
|
735
760
|
event_hook_install();
|
736
761
|
}
|
@@ -837,13 +862,13 @@ rbtrace__process_event(msgpack_object cmd)
|
|
837
862
|
|
838
863
|
rbtracer_detach();
|
839
864
|
|
840
|
-
} else if (0 == strncmp("watch", str.ptr,
|
865
|
+
} else if (0 == strncmp("watch", str.ptr, 5)) {
|
841
866
|
if (ary.size != 2 ||
|
842
867
|
ary.ptr[1].type != MSGPACK_OBJECT_POSITIVE_INTEGER)
|
843
868
|
return;
|
844
869
|
|
845
870
|
unsigned int msec = ary.ptr[1].via.u64;
|
846
|
-
rbtracer_watch(msec);
|
871
|
+
rbtracer_watch(msec, str.size > 5 /* watchcpu */);
|
847
872
|
|
848
873
|
} else if (0 == strncmp("firehose", str.ptr, str.size)) {
|
849
874
|
rbtracer.firehose = true;
|
data/rbtrace.gemspec
CHANGED
data/server.rb
CHANGED
@@ -7,6 +7,14 @@ class String
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
def fib(n)
|
11
|
+
curr = 0
|
12
|
+
succ = 1
|
13
|
+
|
14
|
+
n.times{ curr, succ = succ, curr + succ }
|
15
|
+
curr
|
16
|
+
end
|
17
|
+
|
10
18
|
(reload_test = proc{
|
11
19
|
Object.send(:remove_const, :Test) if defined? Test
|
12
20
|
Test = Class.new do
|
@@ -29,6 +37,8 @@ while true
|
|
29
37
|
|
30
38
|
reload_test.call
|
31
39
|
Test.run
|
40
|
+
|
41
|
+
fib(1024*100)
|
32
42
|
end
|
33
43
|
}.call
|
34
44
|
end
|
data/test.sh
CHANGED
@@ -24,25 +24,28 @@ trace() {
|
|
24
24
|
echo ./bin/rbtrace -p $PID $*
|
25
25
|
echo ------------------------------------------
|
26
26
|
./bin/rbtrace -p $PID $* &
|
27
|
-
sleep
|
27
|
+
sleep 5
|
28
28
|
kill $!
|
29
29
|
wait $! || true
|
30
30
|
echo
|
31
31
|
}
|
32
32
|
|
33
|
-
bin/rbtrace -m sleep --wait 2 --exec ruby -e '10.times{ sleep 0.5 }'
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
#trace -m
|
38
|
-
#trace -m
|
39
|
-
#trace
|
40
|
-
#trace
|
41
|
-
#trace
|
42
|
-
#trace --
|
43
|
-
#trace --gc -m Dir.
|
44
|
-
#trace --
|
45
|
-
#trace -
|
33
|
+
# bin/rbtrace -m sleep --wait 2 --exec ruby -e '10.times{ sleep 0.5 }'
|
34
|
+
|
35
|
+
trace --slowcpu=500
|
36
|
+
|
37
|
+
# trace -m Test.run --devmode
|
38
|
+
# trace -m sleep
|
39
|
+
# trace -m sleep Dir.chdir Dir.pwd Process.pid "String#gsub" "String#*"
|
40
|
+
# trace -m "Kernel#"
|
41
|
+
# trace -m "String#gsub(self,@test)" "String#*(self,__source__)" "String#multiply_vowels(self,self.length,num)"
|
42
|
+
# trace --gc --slow=200
|
43
|
+
# trace --gc -m Dir.
|
44
|
+
# trace --slow=250
|
45
|
+
# trace --slow=250 --slow-methods sleep
|
46
|
+
# trace --gc -m Dir. --slow=250 --slow-methods sleep
|
47
|
+
# trace --gc -m Dir. --slow=250
|
48
|
+
# trace -m Process. Dir.pwd "Proc#call"
|
46
49
|
# trace --firehose
|
47
50
|
|
48
51
|
cleanup
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbtrace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 49
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 17
|
10
|
+
version: 0.3.17
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Aman Gupta
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-11-
|
18
|
+
date: 2011-11-26 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|