chrisa-ruby-dtrace 0.2.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.
- data/History.txt +34 -0
- data/Manifest.txt +58 -0
- data/README.txt +88 -0
- data/Rakefile +73 -0
- data/examples/scsi.rb +442 -0
- data/ext/dof/constants.c +49 -0
- data/ext/dof/dof.h +55 -0
- data/ext/dof/dof_api.c +57 -0
- data/ext/dof/dof_helper.c +82 -0
- data/ext/dof/extconf.rb +4 -0
- data/ext/dof/file.c +56 -0
- data/ext/dof/generator.c +9 -0
- data/ext/dof/header.c +80 -0
- data/ext/dof/parser.c +415 -0
- data/ext/dof/parser.h +10 -0
- data/ext/dof/section.c +302 -0
- data/ext/dtrace_aggdata.c +142 -0
- data/ext/dtrace_api.c +119 -0
- data/ext/dtrace_api.h +150 -0
- data/ext/dtrace_bufdata.c +139 -0
- data/ext/dtrace_dropdata.c +131 -0
- data/ext/dtrace_errdata.c +110 -0
- data/ext/dtrace_hdl.c +577 -0
- data/ext/dtrace_probedata.c +267 -0
- data/ext/dtrace_probedesc.c +78 -0
- data/ext/dtrace_process.c +37 -0
- data/ext/dtrace_program.c +62 -0
- data/ext/dtrace_programinfo.c +60 -0
- data/ext/dtrace_recdesc.c +46 -0
- data/ext/dtrace_util.c +92 -0
- data/ext/extconf.rb +28 -0
- data/ext/stubs.txt +78 -0
- data/lib/dtrace/aggregate.rb +40 -0
- data/lib/dtrace/aggregateset.rb +19 -0
- data/lib/dtrace/consumer.rb +174 -0
- data/lib/dtrace/data.rb +82 -0
- data/lib/dtrace/dof/file.rb +63 -0
- data/lib/dtrace/dof/section/strtab.rb +21 -0
- data/lib/dtrace/dof/section.rb +69 -0
- data/lib/dtrace/dof.rb +8 -0
- data/lib/dtrace/printfrecord.rb +10 -0
- data/lib/dtrace/probe.rb +46 -0
- data/lib/dtrace/probedata.rb +23 -0
- data/lib/dtrace/probedesc.rb +15 -0
- data/lib/dtrace/provider/probedef.rb +24 -0
- data/lib/dtrace/provider.rb +231 -0
- data/lib/dtrace/record.rb +11 -0
- data/lib/dtrace/stackrecord.rb +31 -0
- data/lib/dtrace/tracer.rb +35 -0
- data/lib/dtrace.rb +74 -0
- data/lib/dtraceconsumer.rb +9 -0
- data/plugin/dtrace/README +81 -0
- data/plugin/dtrace/Rakefile +22 -0
- data/plugin/dtrace/bin/dtracer.rb +29 -0
- data/plugin/dtrace/init.rb +7 -0
- data/plugin/dtrace/lib/dtrace_helper.rb +2 -0
- data/plugin/dtrace/lib/dtrace_report.rb +67 -0
- data/plugin/dtrace/lib/dtracer.rb +52 -0
- data/plugin/dtrace/lib/dtracer_client.rb +26 -0
- data/plugin/dtrace/public/stylesheets/dtrace.css +48 -0
- data/plugin/dtrace/scripts/default.d +11 -0
- data/plugin/dtrace/scripts/rails_mysql.d +29 -0
- data/plugin/dtrace/tasks/dtrace.rake +52 -0
- data/plugin/dtrace/test/dtrace_test.rb +8 -0
- data/plugin/dtrace/views/dtrace/_report.rhtml +26 -0
- data/test/apple-dof +0 -0
- data/test/disabled_probe_effect.txt +19 -0
- data/test/dof +0 -0
- data/test/dof2 +0 -0
- data/test/test_disabled_probe_effect.rb +60 -0
- data/test/test_dof_generator.rb +142 -0
- data/test/test_dof_helper.rb +106 -0
- data/test/test_dof_parser.rb +25 -0
- data/test/test_dof_providers.rb +282 -0
- data/test/test_dof_strtabs.rb +92 -0
- data/test/test_dtrace.rb +111 -0
- data/test/test_dtrace_aggregates.rb +56 -0
- data/test/test_dtrace_drops_errors.rb +183 -0
- data/test/test_dtrace_probe.rb +383 -0
- data/test/test_dtrace_probes.rb +400 -0
- data/test/test_dtrace_processes.rb +83 -0
- data/test/test_dtrace_profile.rb +232 -0
- data/test/test_dtrace_provider.rb +153 -0
- data/test/test_dtrace_repeat.rb +51 -0
- data/test/test_dtrace_rubyprobe.rb +52 -0
- data/test/test_dtrace_typefilter.rb +108 -0
- data/test/test_legacy_consumer.rb +56 -0
- metadata +165 -0
data/ext/stubs.txt
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
disassembly of C probe stub:
|
2
|
+
|
3
|
+
/* 3. void probe8(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { */
|
4
|
+
/* <Function: probe8> */
|
5
|
+
/* [ 3] 805133c: pushl %ebp */
|
6
|
+
/* [ 3] 805133d: movl %esp,%ebp */
|
7
|
+
/* [ 3] 805133f: subl $8,%esp */
|
8
|
+
/* 4. TEST_TEST_INT_INT_INT_INT_INT_INT_INT_INT_PROBE(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); */
|
9
|
+
/* [ 4] 8051342: pushl 0x24(%ebp) */
|
10
|
+
/* [ 4] 8051345: pushl 0x20(%ebp) */
|
11
|
+
/* [ 4] 8051348: pushl 0x1c(%ebp) */
|
12
|
+
/* [ 4] 805134b: pushl 0x18(%ebp) */
|
13
|
+
/* [ 4] 805134e: pushl 0x14(%ebp) */
|
14
|
+
/* [ 4] 8051351: pushl 0x10(%ebp) */
|
15
|
+
/* [ 4] 8051354: pushl 0xc(%ebp) */
|
16
|
+
/* [ 4] 8051357: pushl 8(%ebp) */
|
17
|
+
/* [ 4] 805135a: nop */
|
18
|
+
/* [ 4] 805135b: nop */
|
19
|
+
/* [ 4] 805135c: nop */
|
20
|
+
/* [ 4] 805135d: nop */
|
21
|
+
/* [ 4] 805135e: nop */
|
22
|
+
/* [ 4] 805135f: addl $0x20,%esp */
|
23
|
+
/* 5. } */
|
24
|
+
/* [ 5] 8051362: leave */
|
25
|
+
/* [ 5] 8051363: ret */
|
26
|
+
|
27
|
+
Corresponding binary:
|
28
|
+
|
29
|
+
/* 1330 55 89 e5 83 .....^[. ....U... */
|
30
|
+
/* 1340 ec 08 ff 75 24 ff 75 20 ff 75 1c ff 75 18 ff 75 ...u$.u .u..u..u */
|
31
|
+
/* 1350 14 ff 75 10 ff 75 0c ff 75 08 90 90 90 90 90 83 ..u..u.. u....... */
|
32
|
+
/* 1360 c4 20 c9 c3 */
|
33
|
+
|
34
|
+
Hand-built 8-arg stub:
|
35
|
+
|
36
|
+
/* char insns[FUNC_SIZE] = */
|
37
|
+
/* { */
|
38
|
+
/* 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08, */
|
39
|
+
/* 0xff, 0x75, 0x24, */
|
40
|
+
/* 0xff, 0x75, 0x20, */
|
41
|
+
/* 0xff, 0x75, 0x1c, */
|
42
|
+
/* 0xff, 0x75, 0x18, */
|
43
|
+
/* 0xff, 0x75, 0x14, */
|
44
|
+
/* 0xff, 0x75, 0x10, */
|
45
|
+
/* 0xff, 0x75, 0x0c, */
|
46
|
+
/* 0xff, 0x75, 0x08, */
|
47
|
+
/* 0x90, 0x90, 0x90, 0x90, 0x90, */
|
48
|
+
/* 0x83, 0xc4, 0x20, */
|
49
|
+
/* 0xc9, 0xc3 */
|
50
|
+
/* }; */
|
51
|
+
|
52
|
+
disassembly of is_enabled function:
|
53
|
+
|
54
|
+
21. int is_enabled(void) {
|
55
|
+
<Function: is_enabled>
|
56
|
+
[21] 805142a: pushl %ebp
|
57
|
+
[21] 805142b: movl %esp,%ebp
|
58
|
+
[21] 805142d: subl $8,%esp
|
59
|
+
22. return TEST_TEST_PROBE_ENABLED() ? 1 : 0;
|
60
|
+
[22] 8051430: xorl %eax,%eax
|
61
|
+
[22] 8051432: nop
|
62
|
+
[22] 8051433: nop
|
63
|
+
[22] 8051434: nop
|
64
|
+
[22] 8051435: movl %eax,-4(%ebp)
|
65
|
+
[22] 8051438: cmpl $0,-4(%ebp)
|
66
|
+
[22] 805143c: setne %al
|
67
|
+
[22] 805143f: movzbl %al,%eax
|
68
|
+
[22] 8051442: movl %eax,-4(%ebp)
|
69
|
+
[22] 8051445: movl -4(%ebp),%eax
|
70
|
+
23. }
|
71
|
+
[23] 8051448: leave
|
72
|
+
[23] 8051449: ret
|
73
|
+
|
74
|
+
Binary:
|
75
|
+
|
76
|
+
55 89 e5 83 ec 08 ....... ..U.....
|
77
|
+
1430 33 c0 90 90 90 89 45 fc 83 7d fc 00 0f 95 c0 0f 3.....E. .}......
|
78
|
+
1440 b6 c0 89 45 fc 8b 45 fc c9 c3
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
# Represents an aggregation record built from a series of
|
7
|
+
# DtraceAggData records.
|
8
|
+
#
|
9
|
+
# Intended to to built up by calling +add_record+ repeatedly with
|
10
|
+
# Dtrace::AggData objects until a completed Dtrace::Aggregate is
|
11
|
+
# returned. (until a complete record is available, +add_record+
|
12
|
+
# returns nil).
|
13
|
+
#
|
14
|
+
# See consumer.rb for an example of this.
|
15
|
+
class Dtrace
|
16
|
+
class Aggregate
|
17
|
+
attr_reader :value, :tuple
|
18
|
+
|
19
|
+
# Create an empty Dtrace::Aggregate: use +add_record+ to add data.
|
20
|
+
def initialize
|
21
|
+
@tuple = Array.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# Add a Dtrace::AggData record to this aggregate. Returns nil until it
|
25
|
+
# receives a record of aggtype "last", when it returns the complete
|
26
|
+
# Dtrace::Aggregate.
|
27
|
+
def add_record(r)
|
28
|
+
case r.aggtype
|
29
|
+
when "tuple"
|
30
|
+
@tuple << r.value
|
31
|
+
when "value"
|
32
|
+
@value = r.value
|
33
|
+
when "last"
|
34
|
+
return self
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
# A Dtrace::Consumer provides access to the data produced by the running
|
7
|
+
# D program. Having compiled and executed a D program, you typically
|
8
|
+
# create a Dtrace::Consumer, and wait for data.
|
9
|
+
#
|
10
|
+
# You can either wait indefinitely for data, or consume all the data
|
11
|
+
# waiting and then stop: if your D program consists of only of
|
12
|
+
# aggregations, returned by printa() actions in the END block, this
|
13
|
+
# will be the best approach. If you have a mix of trace() and printf()
|
14
|
+
# actions elsewhere, you'll probably want to wait until interrupted,
|
15
|
+
# the D program itself exits, or your program decides it has collected
|
16
|
+
# enough data.
|
17
|
+
#
|
18
|
+
# The two approaches are implemented by the +consume+ and
|
19
|
+
# +consume_once+ methods.
|
20
|
+
#
|
21
|
+
# The +consume+ and +consume_once+ methods accept a block to which is
|
22
|
+
# yielded complete Dtrace::Data objects, one for each probe which fires.
|
23
|
+
#
|
24
|
+
# You must have already started tracing when you call +consume+ or
|
25
|
+
# +consume_once+, so the general structure will look like:
|
26
|
+
#
|
27
|
+
# t = Dtrace.new
|
28
|
+
# progtext = "..."
|
29
|
+
# prog = t.compile progtext
|
30
|
+
# prog.execute
|
31
|
+
# t.go
|
32
|
+
# c = Dtrace::Consumer.new(t)
|
33
|
+
# c.consume_once do |d|
|
34
|
+
# # handle Dtrace::Data objects
|
35
|
+
# # ...
|
36
|
+
# # get bored:
|
37
|
+
# c.finish
|
38
|
+
# end
|
39
|
+
|
40
|
+
class Dtrace
|
41
|
+
class Consumer
|
42
|
+
|
43
|
+
def initialize(t)
|
44
|
+
@t = t
|
45
|
+
@done = false
|
46
|
+
@types = []
|
47
|
+
|
48
|
+
@drophandler = nil
|
49
|
+
@errhandler = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# The consumer callbacks:
|
55
|
+
#
|
56
|
+
# DtraceRecDesc -> rec_consumer
|
57
|
+
# DtraceProbeData -> probe_consumer
|
58
|
+
# DtraceBufData -> buf_consumer
|
59
|
+
#
|
60
|
+
# We expect a sequence of calls to these procs, and we accumulate
|
61
|
+
# data in the @curr Dtrace::Data based on this:
|
62
|
+
#
|
63
|
+
# Dtrace::ProbeData (initial callback for a probe firing)
|
64
|
+
# Dtrace::RecDesc
|
65
|
+
# ...
|
66
|
+
# Dtrace::RecDesc = nil (end of data)
|
67
|
+
#
|
68
|
+
|
69
|
+
def rec_consumer(block)
|
70
|
+
proc do |rec|
|
71
|
+
if rec
|
72
|
+
@curr.add_recdata(rec)
|
73
|
+
else
|
74
|
+
@curr.finish
|
75
|
+
block.call(@curr)
|
76
|
+
@curr = Dtrace::Data.new(@types)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def probe_consumer
|
82
|
+
proc do |probe|
|
83
|
+
@curr.add_probedata(probe)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def buf_consumer
|
88
|
+
proc do |buf|
|
89
|
+
@curr.add_bufdata(buf)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def filter_types(types)
|
94
|
+
@types = types
|
95
|
+
@curr = Dtrace::Data.new(types)
|
96
|
+
end
|
97
|
+
|
98
|
+
public
|
99
|
+
|
100
|
+
# Provide a proc which will be executed when a drop record is
|
101
|
+
# received.
|
102
|
+
def drophandler(&block)
|
103
|
+
@drophandler = block
|
104
|
+
@t.drop_consumer(proc do |drop|
|
105
|
+
if @drophandler
|
106
|
+
@drophandler.call(drop)
|
107
|
+
end
|
108
|
+
end)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Provide a proc which will be executed when an error record is
|
112
|
+
# received.
|
113
|
+
def errhandler(&block)
|
114
|
+
@errhandler = block
|
115
|
+
@t.err_consumer(proc do |err|
|
116
|
+
if @errhandler
|
117
|
+
@errhandler.call(err)
|
118
|
+
end
|
119
|
+
end)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Signals that the client wishes to stop consuming trace data.
|
123
|
+
def finish
|
124
|
+
@t.stop
|
125
|
+
@done = true
|
126
|
+
end
|
127
|
+
|
128
|
+
# Waits for data from the D program, and yields the records returned
|
129
|
+
# to the block given. Returns when the D program exits.
|
130
|
+
#
|
131
|
+
# Pass a list of classes to restrict the types of data returned,
|
132
|
+
# from:
|
133
|
+
#
|
134
|
+
# * DtraceRecord
|
135
|
+
# * DtracePrintfRecord
|
136
|
+
# * DtraceAggregateSet
|
137
|
+
# * DtraceStackRecord
|
138
|
+
#
|
139
|
+
def consume(*types, &block)
|
140
|
+
filter_types(types)
|
141
|
+
@t.buf_consumer(buf_consumer)
|
142
|
+
begin
|
143
|
+
while(true) do
|
144
|
+
@t.sleep
|
145
|
+
work = @t.work(probe_consumer, rec_consumer(block))
|
146
|
+
if (@done || work > 0)
|
147
|
+
break
|
148
|
+
end
|
149
|
+
end
|
150
|
+
ensure
|
151
|
+
@t.stop
|
152
|
+
@t.work(probe_consumer)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Yields the data waiting from the current program, then returns.
|
157
|
+
#
|
158
|
+
# Pass a list of classes to restrict the types of data returned,
|
159
|
+
# from:
|
160
|
+
#
|
161
|
+
# * DtraceRecord
|
162
|
+
# * DtracePrintfRecord
|
163
|
+
# * DtraceAggregateSet
|
164
|
+
# * DtraceStackRecord
|
165
|
+
#
|
166
|
+
def consume_once(*types, &block)
|
167
|
+
filter_types(types)
|
168
|
+
@t.buf_consumer(buf_consumer)
|
169
|
+
@t.stop
|
170
|
+
@t.work(probe_consumer, rec_consumer(block))
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
data/lib/dtrace/data.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
# The object returned from a consumer when a probe fires. Accumulates
|
6
|
+
# records from the callbacks, and is yielded when the data is complete.
|
7
|
+
class Dtrace
|
8
|
+
class Data
|
9
|
+
attr_reader :data
|
10
|
+
attr_reader :probe
|
11
|
+
attr_reader :cpu, :indent, :prefix, :flow
|
12
|
+
|
13
|
+
def initialize(types)
|
14
|
+
@types = types
|
15
|
+
@data = []
|
16
|
+
@curraggset = nil
|
17
|
+
@curragg = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_data(d)
|
21
|
+
if @types.length == 0 || @types.include?(d.class)
|
22
|
+
@data << d
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def finish
|
27
|
+
if @curraggset
|
28
|
+
add_data(@curraggset)
|
29
|
+
@curraggset = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_recdata(rec)
|
34
|
+
if @curraggset
|
35
|
+
add_data(@curraggset)
|
36
|
+
@curraggset = nil
|
37
|
+
end
|
38
|
+
if rec.action == "printa"
|
39
|
+
@curraggset = Dtrace::AggregateSet.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_probedata(probedata)
|
44
|
+
probedata.each_record do |p|
|
45
|
+
add_data(p)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Record the probe that fired, and CPU/indent/prefix/flow
|
49
|
+
@probe = probedata.probe
|
50
|
+
@cpu = probedata.cpu
|
51
|
+
@indent = probedata.indent
|
52
|
+
@prefix = probedata.prefix
|
53
|
+
@flow = probedata.flow
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_bufdata(buf)
|
57
|
+
r = buf.record
|
58
|
+
# buf records can be empty (trace();)
|
59
|
+
if r
|
60
|
+
case r.class.to_s
|
61
|
+
when Dtrace::StackRecord.to_s
|
62
|
+
add_data(r)
|
63
|
+
when Dtrace::Record.to_s
|
64
|
+
add_data(r)
|
65
|
+
when Dtrace::PrintfRecord.to_s
|
66
|
+
add_data(r)
|
67
|
+
when Dtrace::AggData.to_s
|
68
|
+
if @curragg == nil
|
69
|
+
@curragg = Dtrace::Aggregate.new
|
70
|
+
end
|
71
|
+
if agg = @curragg.add_record(r)
|
72
|
+
if @curraggset
|
73
|
+
@curraggset.add_aggregate(@curragg)
|
74
|
+
end
|
75
|
+
@curragg = nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace::Dof::File
|
7
|
+
include Dtrace::Dof::Constants
|
8
|
+
attr_accessor :sections
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@sections = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
hdr = Dtrace::Dof::Header.new
|
16
|
+
hdr.secnum = @sections.length
|
17
|
+
filesz = hdr.hdrlen
|
18
|
+
loadsz = filesz
|
19
|
+
dof_version = 1
|
20
|
+
|
21
|
+
@sections.each do |s|
|
22
|
+
# Presence of is_enabled probes forces DOF version 2.
|
23
|
+
if s.section_type == DOF_SECT_PRENOFFS
|
24
|
+
dof_version = 2
|
25
|
+
end
|
26
|
+
|
27
|
+
length = s.generate
|
28
|
+
s.offset = filesz
|
29
|
+
|
30
|
+
pad = 0
|
31
|
+
if s.align > 1
|
32
|
+
i = s.offset.to_f % s.align
|
33
|
+
if i > 0
|
34
|
+
pad = (s.align - i).to_i
|
35
|
+
s.offset = pad + s.offset
|
36
|
+
s.pad = "\000" * pad
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
s.size = length + pad
|
41
|
+
|
42
|
+
loadsz += s.size if (s.flags & 1) == 1 # DOF_SECF_LOAD
|
43
|
+
filesz += s.size
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
hdr.loadsz = loadsz
|
48
|
+
hdr.filesz = filesz
|
49
|
+
hdr.dof_version = dof_version
|
50
|
+
|
51
|
+
self << hdr.generate
|
52
|
+
|
53
|
+
@sections.each do |s|
|
54
|
+
self << s.generate_header
|
55
|
+
end
|
56
|
+
|
57
|
+
@sections.each do |s|
|
58
|
+
self << s.pad if s.pad
|
59
|
+
self << s.dof
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace::Dof::Section::Strtab < Dtrace::Dof::Section
|
7
|
+
def initialize(index)
|
8
|
+
super(DOF_SECT_STRTAB, index)
|
9
|
+
self.data = []
|
10
|
+
@idx = 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(string)
|
14
|
+
idx = @idx
|
15
|
+
string = string.to_s
|
16
|
+
@idx += (string.length + 1)
|
17
|
+
self.data << string
|
18
|
+
return idx
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'dtrace/dof/section/strtab'
|
7
|
+
|
8
|
+
class Dtrace::Dof::Section
|
9
|
+
include Dtrace::Dof::Constants
|
10
|
+
attr_writer :entsize
|
11
|
+
attr_accessor :flags, :data, :offset, :align, :pad, :size
|
12
|
+
attr_reader :section_type, :dof
|
13
|
+
|
14
|
+
def initialize(type, index)
|
15
|
+
@section_type = type
|
16
|
+
@index = index
|
17
|
+
@flags = 1 # DOF_SECF_LOAD
|
18
|
+
@data = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate
|
22
|
+
case @section_type
|
23
|
+
when DOF_SECT_COMMENTS
|
24
|
+
@align = 1
|
25
|
+
@dof = dof_generate_comments
|
26
|
+
when DOF_SECT_STRTAB
|
27
|
+
@align = 1
|
28
|
+
@dof = dof_generate_strtab
|
29
|
+
when DOF_SECT_PROBES
|
30
|
+
@align = 8
|
31
|
+
@dof = dof_generate_probes
|
32
|
+
when DOF_SECT_PRARGS
|
33
|
+
@align = 1
|
34
|
+
@dof = dof_generate_prargs
|
35
|
+
when DOF_SECT_PROFFS
|
36
|
+
@align = 4
|
37
|
+
@dof = dof_generate_proffs
|
38
|
+
when DOF_SECT_PRENOFFS
|
39
|
+
@align = 4
|
40
|
+
@dof = dof_generate_prenoffs
|
41
|
+
when DOF_SECT_PROVIDER
|
42
|
+
@align = 4
|
43
|
+
@dof = dof_generate_provider
|
44
|
+
when DOF_SECT_RELTAB
|
45
|
+
@align = 8
|
46
|
+
@dof = dof_generate_reltab
|
47
|
+
when DOF_SECT_URELHDR
|
48
|
+
@align = 4
|
49
|
+
@dof = dof_generate_relhdr
|
50
|
+
when DOF_SECT_UTSNAME
|
51
|
+
@align = 1
|
52
|
+
@dof = dof_generate_utsname
|
53
|
+
else
|
54
|
+
@dof = ''
|
55
|
+
end
|
56
|
+
|
57
|
+
begin
|
58
|
+
if @data.class == Array
|
59
|
+
@entsize = @dof.length / @data.length
|
60
|
+
else
|
61
|
+
@entsize = 0
|
62
|
+
end
|
63
|
+
rescue ZeroDivisionError
|
64
|
+
@entsize = 0
|
65
|
+
end
|
66
|
+
|
67
|
+
return @dof.length
|
68
|
+
end
|
69
|
+
end
|
data/lib/dtrace/dof.rb
ADDED
data/lib/dtrace/probe.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
|
5
|
+
class Dtrace
|
6
|
+
# Using dynamically created USDT probes in Ruby programs.
|
7
|
+
#
|
8
|
+
# Having created the following probes with Dtrace::Provider:
|
9
|
+
#
|
10
|
+
# 74777 action_controller12297 action_controller.so process_finish process-finish
|
11
|
+
# 74778 action_controller12297 action_controller.so process_start process-start
|
12
|
+
#
|
13
|
+
# you can fire them with the following Ruby statements:
|
14
|
+
#
|
15
|
+
# Dtrace::Probe::ActionController.process_start do |p|
|
16
|
+
# p.fire(request.url)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Note that the generated class corresponding to the provider is
|
20
|
+
# simply the provider class, camelized.
|
21
|
+
#
|
22
|
+
# The generated method corresponding to the probe name (with -
|
23
|
+
# replaced by _) yields a probe object, on which you can call fire(),
|
24
|
+
# passing arguments of the appropriate types -- you are responsible
|
25
|
+
# for any type conversions necessary.
|
26
|
+
#
|
27
|
+
# fire() takes as many arguments as you defined for the probe: if
|
28
|
+
# you have generated a list of arguments to pass to fire(), use the
|
29
|
+
# splat operator to expand the list:
|
30
|
+
#
|
31
|
+
# Dtrace::Probe::MyProvider.my_probe do |p|
|
32
|
+
# args_list = [ some operation to get a list ]
|
33
|
+
# p.fire(*args_list)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# This yield/fire() syntax exposes the is-enabled feature of the
|
37
|
+
# generated USDT probes: if the probe is not enabled, then the yield
|
38
|
+
# does not happen: this allows you to put relatively expensive work
|
39
|
+
# in the block, and know it is only called if the probe is enabled.
|
40
|
+
# This way, the probe-disabled overhead of these providers is
|
41
|
+
# reduced to a single method call, to a C-implemented method which
|
42
|
+
# simply wraps the DTrace IS_ENABLED() macro for the probe.
|
43
|
+
#
|
44
|
+
class Probe
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace
|
7
|
+
class ProbeData
|
8
|
+
|
9
|
+
def records
|
10
|
+
records = Array.new
|
11
|
+
self.each_record do |rec|
|
12
|
+
records << rec
|
13
|
+
end
|
14
|
+
records
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
rs = self.records
|
19
|
+
rs.map {|r| r.value }.join ', '
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace
|
7
|
+
class Provider
|
8
|
+
class ProbeDef
|
9
|
+
attr_reader :name, :function
|
10
|
+
attr_accessor :args
|
11
|
+
|
12
|
+
def initialize(name, function)
|
13
|
+
@name = name.to_s
|
14
|
+
@function = function.to_s
|
15
|
+
@args = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def argc
|
19
|
+
@args.length
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|