ruby-dtrace 0.0.6 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/History.txt +21 -0
  2. data/Manifest.txt +86 -19
  3. data/README.txt +48 -6
  4. data/Rakefile +61 -20
  5. data/examples/scsi.rb +1 -1
  6. data/ext/dof/Makefile +154 -0
  7. data/ext/dof/constants.c +57 -0
  8. data/ext/dof/dof.h +56 -0
  9. data/ext/dof/dof_api.c +58 -0
  10. data/ext/dof/dof_helper.c +82 -0
  11. data/ext/dof/extconf.rb +4 -0
  12. data/ext/dof/file.c +90 -0
  13. data/ext/dof/generator.c +9 -0
  14. data/ext/dof/header.c +79 -0
  15. data/ext/dof/mkmf.log +10 -0
  16. data/ext/dof/parser.c +415 -0
  17. data/ext/dof/parser.h +10 -0
  18. data/ext/dof/section.c +312 -0
  19. data/ext/dtrace_aggdata.c +2 -2
  20. data/ext/dtrace_api.c +46 -34
  21. data/ext/dtrace_api.h +31 -7
  22. data/ext/dtrace_bufdata.c +3 -3
  23. data/ext/dtrace_hdl.c +66 -3
  24. data/ext/dtrace_probedata.c +4 -4
  25. data/ext/{dtrace_probe.c → dtrace_probedesc.c} +7 -7
  26. data/ext/extconf.rb +25 -0
  27. data/ext/i386-darwin/dtrace_probe.c +278 -0
  28. data/ext/i386-solaris/dtrace_probe.c +225 -0
  29. data/ext/stubs.txt +78 -0
  30. data/lib/dtrace.rb +34 -13
  31. data/lib/dtrace/aggregate.rb +40 -0
  32. data/lib/dtrace/aggregateset.rb +19 -0
  33. data/lib/dtrace/consumer.rb +174 -0
  34. data/lib/dtrace/data.rb +82 -0
  35. data/lib/dtrace/dof.rb +8 -0
  36. data/lib/dtrace/dof/file.rb +64 -0
  37. data/lib/dtrace/dof/section.rb +75 -0
  38. data/lib/dtrace/dof/section/strtab.rb +28 -0
  39. data/lib/{dtraceprintfrecord.rb → dtrace/printfrecord.rb} +4 -2
  40. data/lib/dtrace/probe.rb +3 -6
  41. data/lib/dtrace/probedata.rb +23 -0
  42. data/lib/dtrace/probedesc.rb +15 -0
  43. data/lib/dtrace/provider.rb +190 -169
  44. data/lib/dtrace/provider/klass.rb +33 -0
  45. data/lib/dtrace/provider/probedef.rb +24 -0
  46. data/lib/{dtracerecord.rb → dtrace/record.rb} +4 -2
  47. data/lib/{dtracestackrecord.rb → dtrace/stackrecord.rb} +10 -8
  48. data/lib/dtrace/version.rb +9 -0
  49. data/lib/dtraceconsumer.rb +3 -167
  50. data/plugin/dtrace/lib/dtracer.rb +4 -4
  51. data/test/apple-dof +0 -0
  52. data/test/disabled_probe_effect.txt +19 -0
  53. data/test/dof +0 -0
  54. data/test/dof2 +0 -0
  55. data/test/test_disabled_probe_effect.rb +56 -0
  56. data/test/test_dof_generator.rb +142 -0
  57. data/test/test_dof_helper.rb +106 -0
  58. data/test/test_dof_parser.rb +27 -0
  59. data/test/test_dof_providers.rb +278 -0
  60. data/test/test_dof_strtabs.rb +98 -0
  61. data/test/test_dtrace.rb +67 -1
  62. data/test/test_dtrace_aggregates.rb +5 -5
  63. data/test/test_dtrace_drops_errors.rb +5 -5
  64. data/test/test_dtrace_probe.rb +385 -0
  65. data/test/test_dtrace_probes.rb +414 -0
  66. data/test/test_dtrace_processes.rb +2 -2
  67. data/test/test_dtrace_profile.rb +12 -12
  68. data/test/test_dtrace_provider.rb +138 -0
  69. data/test/test_dtrace_repeat.rb +1 -1
  70. data/test/test_dtrace_rubyprobe.rb +3 -1
  71. data/test/test_dtrace_typefilter.rb +9 -9
  72. data/test/test_legacy_consumer.rb +56 -0
  73. metadata +112 -71
  74. data/lib/dtrace/provider/osx.rb +0 -25
  75. data/lib/dtrace/provider/solaris.rb +0 -29
  76. data/lib/dtraceaggregate.rb +0 -37
  77. data/lib/dtraceaggregateset.rb +0 -17
  78. data/lib/dtracedata.rb +0 -80
  79. data/lib/dtraceprobe.rb +0 -13
  80. data/lib/dtraceprobedata.rb +0 -21
  81. data/test/test_dynusdt.rb +0 -135
@@ -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
@@ -4,15 +4,17 @@
4
4
  #
5
5
 
6
6
  require 'dtrace_api'
7
- require 'dtracerecord'
7
+ require 'dtrace/record'
8
+ require 'dtrace/consumer'
8
9
  require 'dtraceconsumer'
9
- require 'dtraceaggregate'
10
- require 'dtraceaggregateset'
11
- require 'dtraceprobedata'
12
- require 'dtraceprobe'
13
- require 'dtracestackrecord'
14
- require 'dtraceprintfrecord'
15
- require 'dtracedata'
10
+ require 'dtrace/aggregate'
11
+ require 'dtrace/aggregateset'
12
+ require 'dtrace/probedata'
13
+ require 'dtrace/probedesc'
14
+ require 'dtrace/stackrecord'
15
+ require 'dtrace/printfrecord'
16
+ require 'dtrace/data'
17
+ require 'dtrace/version'
16
18
 
17
19
  # A DTrace handle. Provides methods for inspecting available probes,
18
20
  # compiling and running programs, and for setting up callbacks to
@@ -22,10 +24,10 @@ require 'dtracedata'
22
24
  #
23
25
  # * Create a handle with Dtrace.new
24
26
  # * Set options
25
- # * Compile the program, possibly inspecting the return DtraceProgramInfo
27
+ # * Compile the program, possibly inspecting the return Dtrace::ProgramInfo
26
28
  # * Execute the program
27
29
  # * Start tracing
28
- # * Consume data, either directly by setting up callbacks, or using a DtraceConsumer.
30
+ # * Consume data, either directly by setting up callbacks, or using a Dtrace::Consumer.
29
31
  # * Stop tracing
30
32
  #
31
33
  # === Listing probes
@@ -57,18 +59,37 @@ require 'dtracedata'
57
59
  # t.go
58
60
  # p.continue
59
61
  #
60
- # c = DtraceConsumer.new(t)
62
+ # c = Dtrace::Consumer.new(t)
61
63
  # c.consume do |d|
62
64
  # ..
63
65
  # end
64
66
 
65
67
  class Dtrace
66
- VERSION = '0.0.6'
67
-
68
68
  STATUS_NONE = 0
69
69
  STATUS_OKAY = 1
70
70
  STATUS_EXITED = 2
71
71
  STATUS_FILLED = 3
72
72
  STATUS_STOPPED = 4
73
+
74
+ # Yields each probe on the system, optionally matching against a
75
+ # probe specification:
76
+ #
77
+ # e.g.
78
+ # syscall::: -> all probes in the syscall provider
79
+ # pid123:::return -> all return probes in pid 123.
80
+ #
81
+ def each_probe(match=nil, &block)
82
+ if match
83
+ parts = match.split(':', 4)
84
+ begin
85
+ each_probe_match(*parts, &block)
86
+ rescue ArgumentError => e
87
+ raise Dtrace::Exception.new("each_probe: probe specification expected (e.g. 'provider:::')")
88
+ end
89
+ else
90
+ each_probe_all(&block)
91
+ end
92
+ end
93
+
73
94
  end
74
95
 
@@ -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,19 @@
1
+ #
2
+ # Ruby-Dtrace
3
+ # (c) 2007 Chris Andrews <chris@nodnol.org>
4
+ #
5
+
6
+ class Dtrace
7
+ class AggregateSet
8
+ attr_reader :data
9
+
10
+ def initialize
11
+ @data = Array.new
12
+ end
13
+
14
+ def add_aggregate(agg)
15
+ @data << agg
16
+ end
17
+
18
+ end
19
+ 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
@@ -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