ruby-dtrace 0.0.6 → 0.2.8

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.
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