ruby-dtrace 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -202,17 +202,17 @@ VALUE dtraceprobedata_each_record(VALUE self)
202
202
  dtrace_probedata_t *data;
203
203
  dtrace_eprobedesc_t *eprobe;
204
204
  dtrace_recdesc_t *rec;
205
- dtrace_hdl_t *handle;
205
+ dtrace_handle_t *handle;
206
206
  dtrace_actkind_t act;
207
207
  int i;
208
208
  caddr_t addr;
209
209
  VALUE dtracerecord;
210
- VALUE dtracehandle;
210
+ VALUE dtrace;
211
211
  VALUE v;
212
212
 
213
213
  Data_Get_Struct(self, dtrace_probedata_t, data);
214
- dtracehandle = rb_iv_get(self, "@handle");
215
- Data_Get_Struct(dtracehandle, dtrace_hdl_t, handle);
214
+ dtrace = rb_iv_get(self, "@handle");
215
+ Data_Get_Struct(dtrace, dtrace_handle_t, handle);
216
216
 
217
217
  eprobe = data->dtpda_edesc;
218
218
 
@@ -228,8 +228,8 @@ VALUE dtraceprobedata_each_record(VALUE self)
228
228
  case DTRACEACT_USTACK:
229
229
  case DTRACEACT_JSTACK:
230
230
  /* Stack records come from bufdata */
231
- /* v = _handle_stack_record(handle, addr, rec); */
232
- /* v = _handle_ustack_record(handle, addr, rec); */
231
+ /* v = _handle_stack_record(handle->hdl, addr, rec); */
232
+ /* v = _handle_ustack_record(handle->hdl, addr, rec); */
233
233
  break;
234
234
  case DTRACEACT_PRINTA:
235
235
  /* don't want the probedata record for a printa() action */
data/ext/dtrace_program.c CHANGED
@@ -24,17 +24,22 @@ VALUE dtraceprogram_exec(VALUE self)
24
24
  {
25
25
  dtrace_prog_t *prog;
26
26
  dtrace_proginfo_t *proginfo;
27
- dtrace_hdl_t *handle;
27
+ dtrace_handle_t *handle;
28
28
  VALUE dtrace;
29
29
  VALUE dtraceprograminfo;
30
30
  int ret;
31
31
 
32
32
  Data_Get_Struct(self, dtrace_prog_t, prog);
33
- dtrace = rb_iv_get(self, "@dtrace");
34
- Data_Get_Struct(dtrace, dtrace_hdl_t, handle);
33
+ dtrace = rb_iv_get(self, "@handle");
34
+ Data_Get_Struct(dtrace, dtrace_handle_t, handle);
35
35
 
36
36
  proginfo = ALLOC(dtrace_proginfo_t);
37
- ret = dtrace_program_exec(handle, prog, proginfo);
37
+ if (!proginfo) {
38
+ rb_raise(eDtraceException, "alloc failed");
39
+ return Qnil;
40
+ }
41
+
42
+ ret = dtrace_program_exec(handle->hdl, prog, proginfo);
38
43
 
39
44
  if (ret == 0) {
40
45
  dtraceprograminfo = Data_Wrap_Struct(cDtraceProgramInfo, 0, NULL, proginfo);
@@ -42,7 +47,7 @@ VALUE dtraceprogram_exec(VALUE self)
42
47
  }
43
48
 
44
49
  if (ret < 0)
45
- rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
50
+ rb_raise(eDtraceException, dtrace_errmsg(handle->hdl, dtrace_errno(handle->hdl)));
46
51
 
47
52
  return Qnil;
48
53
  }
data/lib/dtrace.rb CHANGED
@@ -63,7 +63,7 @@ require 'dtracedata'
63
63
  # end
64
64
 
65
65
  class Dtrace
66
- VERSION = '0.0.4'
66
+ VERSION = '0.0.5'
67
67
 
68
68
  STATUS_NONE = 0
69
69
  STATUS_OKAY = 1
@@ -41,8 +41,11 @@ class DtraceConsumer
41
41
 
42
42
  def initialize(t)
43
43
  @t = t
44
- @curr = DtraceData.new
45
44
  @done = false
45
+ @types = []
46
+
47
+ @drophandler = nil
48
+ @errhandler = nil
46
49
  end
47
50
 
48
51
  private
@@ -69,7 +72,7 @@ class DtraceConsumer
69
72
  else
70
73
  @curr.finish
71
74
  block.call(@curr)
72
- @curr = DtraceData.new
75
+ @curr = DtraceData.new(@types)
73
76
  end
74
77
  end
75
78
  end
@@ -85,9 +88,36 @@ class DtraceConsumer
85
88
  @curr.add_bufdata(buf)
86
89
  end
87
90
  end
91
+
92
+ def filter_types(types)
93
+ @types = types
94
+ @curr = DtraceData.new(types)
95
+ end
88
96
 
89
97
  public
90
98
 
99
+ # Provide a proc which will be executed when a drop record is
100
+ # received.
101
+ def drophandler(&block)
102
+ @drophandler = block
103
+ @t.drop_consumer(proc do |drop|
104
+ if @drophandler
105
+ @drophandler.call(drop)
106
+ end
107
+ end)
108
+ end
109
+
110
+ # Provide a proc which will be executed when an error record is
111
+ # received.
112
+ def errhandler(&block)
113
+ @errhandler = block
114
+ @t.err_consumer(proc do |err|
115
+ if @errhandler
116
+ @errhandler.call(err)
117
+ end
118
+ end)
119
+ end
120
+
91
121
  # Signals that the client wishes to stop consuming trace data.
92
122
  def finish
93
123
  @t.stop
@@ -96,7 +126,17 @@ class DtraceConsumer
96
126
 
97
127
  # Waits for data from the D program, and yields the records returned
98
128
  # to the block given. Returns when the D program exits.
99
- def consume(&block)
129
+ #
130
+ # Pass a list of classes to restrict the types of data returned,
131
+ # from:
132
+ #
133
+ # * DtraceRecord
134
+ # * DtracePrintfRecord
135
+ # * DtraceAggregateSet
136
+ # * DtraceStackRecord
137
+ #
138
+ def consume(*types, &block)
139
+ filter_types(types)
100
140
  @t.buf_consumer(buf_consumer)
101
141
  begin
102
142
  while(true) do
@@ -113,7 +153,17 @@ class DtraceConsumer
113
153
  end
114
154
 
115
155
  # Yields the data waiting from the current program, then returns.
116
- def consume_once(&block)
156
+ #
157
+ # Pass a list of classes to restrict the types of data returned,
158
+ # from:
159
+ #
160
+ # * DtraceRecord
161
+ # * DtracePrintfRecord
162
+ # * DtraceAggregateSet
163
+ # * DtraceStackRecord
164
+ #
165
+ def consume_once(*types, &block)
166
+ filter_types(types)
117
167
  @t.buf_consumer(buf_consumer)
118
168
  @t.stop
119
169
  @t.work(probe_consumer, rec_consumer(block))
data/lib/dtracedata.rb CHANGED
@@ -9,22 +9,29 @@ class DtraceData
9
9
  attr_reader :probe
10
10
  attr_reader :cpu, :indent, :prefix, :flow
11
11
 
12
- def initialize
12
+ def initialize(types)
13
+ @types = types
13
14
  @data = []
14
15
  @curraggset = nil
15
16
  @curragg = nil
16
17
  end
17
18
 
19
+ def add_data(d)
20
+ if @types.length == 0 || @types.include?(d.class)
21
+ @data << d
22
+ end
23
+ end
24
+
18
25
  def finish
19
26
  if @curraggset
20
- @data << @curraggset
27
+ add_data(@curraggset)
21
28
  @curraggset = nil
22
29
  end
23
30
  end
24
31
 
25
32
  def add_recdata(rec)
26
33
  if @curraggset
27
- @data << @curraggset
34
+ add_data(@curraggset)
28
35
  @curraggset = nil
29
36
  end
30
37
  if rec.action == "printa"
@@ -34,7 +41,7 @@ class DtraceData
34
41
 
35
42
  def add_probedata(probedata)
36
43
  probedata.each_record do |p|
37
- @data << p
44
+ add_data(p)
38
45
  end
39
46
 
40
47
  # Record the probe that fired, and CPU/indent/prefix/flow
@@ -51,11 +58,11 @@ class DtraceData
51
58
  if r
52
59
  case r.class.to_s
53
60
  when DtraceStackRecord.to_s
54
- @data << r
61
+ add_data(r)
55
62
  when DtraceRecord.to_s
56
- @data << r
63
+ add_data(r)
57
64
  when DtracePrintfRecord.to_s
58
- @data << r
65
+ add_data(r)
59
66
  when DtraceAggData.to_s
60
67
  if @curragg == nil
61
68
  @curragg = DtraceAggregate.new
@@ -0,0 +1,183 @@
1
+ #
2
+ # Ruby-Dtrace
3
+ # (c) 2007 Chris Andrews <chris@nodnol.org>
4
+ #
5
+
6
+ require 'dtrace'
7
+ require 'test/unit'
8
+
9
+ # Tests for the DropData record.
10
+
11
+ class TestDtraceDropsErrors < Test::Unit::TestCase
12
+
13
+ def test_drops
14
+ t = Dtrace.new
15
+ t.setopt("bufsize", "512")
16
+ t.setopt("strsize", "1024")
17
+
18
+ # drp.DTRACEDROP_PRINCIPAL.d
19
+ progtext = <<EOD
20
+ BEGIN
21
+ {
22
+ trace("Harding");
23
+ trace("Hoover");
24
+ trace("Nixon");
25
+ trace("Bush");
26
+ }
27
+
28
+ BEGIN
29
+ {
30
+ exit(0);
31
+ }
32
+ EOD
33
+
34
+ prog = t.compile progtext
35
+ prog.execute
36
+
37
+ c = DtraceConsumer.new(t)
38
+ assert c
39
+
40
+ i = 0
41
+ c.drophandler do |d|
42
+ assert_match(/1 drop on CPU [0-9]+/, d.msg)
43
+ assert_equal "drop to principal buffer", d.kind
44
+ assert_not_nil d.cpu
45
+ assert_equal 1, d.drops
46
+ assert_not_nil d.total
47
+ i = 1
48
+ end
49
+
50
+ t.go
51
+ c.consume do |d|
52
+ end
53
+
54
+ assert_equal 1, i
55
+ end
56
+
57
+ def test_error_handler_too_late
58
+ t = Dtrace.new
59
+ t.setopt("bufsize", "512")
60
+ t.setopt("strsize", "1024")
61
+
62
+ progtext = <<EOD
63
+ BEGIN
64
+ {
65
+ *(char *)NULL;
66
+ }
67
+ EOD
68
+
69
+ prog = t.compile progtext
70
+ prog.execute
71
+ t.go
72
+
73
+ c = DtraceConsumer.new(t)
74
+ assert c
75
+
76
+ # since we've already said "go", we now can't apply an error
77
+ # handler (DTrace will let us, but won't call it).
78
+ assert_raise(DtraceException) do
79
+ c.errhandler do |d|
80
+ # nothing
81
+ end
82
+ end
83
+
84
+ end
85
+
86
+ def test_errors
87
+ t = Dtrace.new
88
+ t.setopt("bufsize", "512")
89
+ t.setopt("strsize", "1024")
90
+
91
+ progtext = <<EOD
92
+ BEGIN
93
+ {
94
+ *(char *)NULL;
95
+ }
96
+ EOD
97
+
98
+ prog = t.compile progtext
99
+ prog.execute
100
+
101
+ c = DtraceConsumer.new(t)
102
+ assert c
103
+
104
+ i = 0
105
+ c.errhandler do |d|
106
+ assert_match(/error on enabled probe ID [0-9]+ \(ID [0-9]+: dtrace:::BEGIN\): invalid address \(0x0\) in action #1 at DIF offset 16/, d.msg)
107
+ assert_not_nil d.cpu
108
+ assert d.action
109
+ assert d.offset
110
+ assert d.fault
111
+ assert_not_nil d.addr
112
+ i = 1
113
+ end
114
+
115
+ t.go
116
+ c.consume_once do |d|
117
+ end
118
+
119
+ assert_equal 1, i
120
+ end
121
+
122
+ def test_error_and_drop_handler
123
+
124
+ t = Dtrace.new
125
+ t.setopt("bufsize", "512")
126
+ t.setopt("strsize", "1024")
127
+
128
+ progtext = <<EOD
129
+ BEGIN
130
+ {
131
+ trace("Harding");
132
+ trace("Hoover");
133
+ trace("Nixon");
134
+ trace("Bush");
135
+ }
136
+
137
+ BEGIN
138
+ {
139
+ *(char *)NULL;
140
+ }
141
+
142
+ ERROR
143
+ {
144
+ exit(0);
145
+ }
146
+ EOD
147
+
148
+ prog = t.compile progtext
149
+ prog.execute
150
+
151
+ c = DtraceConsumer.new(t)
152
+ assert c
153
+
154
+ errors = 0
155
+ c.errhandler do |d|
156
+ assert_match(/error on enabled probe ID [0-9]+ \(ID [0-9]+: dtrace:::BEGIN\): invalid address \(0x0\) in action #1 at DIF offset 16/, d.msg)
157
+ assert_not_nil d.cpu
158
+ assert d.action
159
+ assert d.offset
160
+ assert d.fault
161
+ assert_not_nil d.addr
162
+ errors = 1
163
+ end
164
+
165
+ drops = 0
166
+ c.drophandler do |d|
167
+ assert_match(/1 drop on CPU [0-9]+/, d.msg)
168
+ assert_equal "drop to principal buffer", d.kind
169
+ assert_not_nil d.cpu
170
+ assert_equal 1, d.drops
171
+ assert_not_nil d.total
172
+ drops = 1
173
+ end
174
+
175
+ t.go
176
+ c.consume do |d|
177
+ end
178
+
179
+ assert_equal 1, errors
180
+ assert_equal 1, drops
181
+ end
182
+
183
+ end
@@ -0,0 +1,108 @@
1
+ #
2
+ # Ruby-Dtrace
3
+ # (c) 2007 Chris Andrews <chris@nodnol.org>
4
+ #
5
+
6
+ require 'dtrace'
7
+ require 'test/unit'
8
+
9
+ # Tests for the feature allowing you to filter DtraceData types
10
+
11
+ class TestDtraceTypefilter < Test::Unit::TestCase
12
+ def test_filter
13
+ t = Dtrace.new
14
+ t.setopt("bufsize", "4m")
15
+ t.setopt("aggsize", "4m")
16
+
17
+ progtext =<<EOD
18
+ profile-1000
19
+ {
20
+ @a[execname] = count();
21
+ @b[execname] = count();
22
+ }
23
+
24
+ profile-10
25
+ {
26
+ trace("foo");
27
+ printa(@a);
28
+ printf("bar");
29
+ printa(@b);
30
+ }
31
+ EOD
32
+
33
+ prog = t.compile progtext
34
+ prog.execute
35
+ t.go
36
+
37
+ sleep 1
38
+
39
+ c = DtraceConsumer.new(t)
40
+ assert c
41
+
42
+ data = []
43
+ c.consume_once(DtraceAggregateSet) do |d|
44
+ data << d
45
+ end
46
+
47
+ assert data.length > 0
48
+ data.each do |d|
49
+ assert d
50
+ assert_equal DtraceData, d.class
51
+ d.data.each do |agg|
52
+ assert_equal DtraceAggregateSet, agg.class
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ def test_filter_two_classes
59
+ t = Dtrace.new
60
+ t.setopt("bufsize", "4m")
61
+ t.setopt("aggsize", "4m")
62
+
63
+ progtext =<<EOD
64
+ profile-1000
65
+ {
66
+ @a[execname] = count();
67
+ @b[execname] = count();
68
+ }
69
+
70
+ profile-10
71
+ {
72
+ trace("foo");
73
+ printa(@a);
74
+ printf("bar");
75
+ printa(@b);
76
+ }
77
+ EOD
78
+
79
+ prog = t.compile progtext
80
+ prog.execute
81
+ t.go
82
+
83
+ sleep 1
84
+
85
+ c = DtraceConsumer.new(t)
86
+ assert c
87
+
88
+ data = []
89
+ c.consume_once(DtraceAggregateSet, DtracePrintfRecord) do |d|
90
+ data << d
91
+ end
92
+
93
+ assert data.length > 0
94
+ data.each do |d|
95
+ assert d
96
+ assert_equal DtraceData, d.class
97
+ d.data.each do |r|
98
+ if r.respond_to?(:add_aggregate)
99
+ assert_equal DtraceAggregateSet, r.class
100
+ else
101
+ assert_equal DtracePrintfRecord, r.class
102
+ end
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ end