ruby-dtrace 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,10 @@
1
+ == 0.0.2 / 2007-12-07
2
+
3
+ * Implement the dtrace_work-based API
4
+ * Add a "Consumer" class
5
+ * Update Rails plugin to use new API
6
+
1
7
  == 0.0.1 / 2007-12-01
2
8
 
3
9
  * Initial public release.
10
+
data/Manifest.txt CHANGED
@@ -2,16 +2,24 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
- ext/dtrace_aggregate.c
5
+ ext/dtrace_aggdata.c
6
6
  ext/dtrace_api.c
7
7
  ext/dtrace_api.h
8
+ ext/dtrace_bufdata.c
8
9
  ext/dtrace_hdl.c
9
10
  ext/dtrace_probe.c
11
+ ext/dtrace_probedata.c
10
12
  ext/dtrace_program.c
11
13
  ext/dtrace_programinfo.c
12
14
  ext/dtrace_recdesc.c
15
+ ext/dtrace_util.c
13
16
  ext/extconf.rb
14
17
  lib/dtrace.rb
18
+ lib/dtraceaggregate.rb
19
+ lib/dtraceconsumer.rb
20
+ lib/dtraceprobe.rb
21
+ lib/dtraceprobedata.rb
22
+ lib/dtracerecord.rb
15
23
  plugin/dtrace/README
16
24
  plugin/dtrace/Rakefile
17
25
  plugin/dtrace/bin/dtracer.rb
@@ -26,3 +34,4 @@ plugin/dtrace/tasks/dtrace.rake
26
34
  plugin/dtrace/test/dtrace_test.rb
27
35
  plugin/dtrace/views/dtrace/_report.rhtml
28
36
  test/test_dtrace.rb
37
+ test/test_dtrace_workapi.rb
data/Rakefile CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
- require './lib/dtrace'
5
+
6
+ $: << './lib'
7
+ require 'dtrace'
6
8
 
7
9
  Hoe.new('ruby-dtrace', Dtrace::VERSION) do |p|
8
10
  p.rubyforge_name = 'ruby-dtrace'
@@ -0,0 +1,139 @@
1
+ /* Ruby-Dtrace
2
+ * (c) 2007 Chris Andrews <chris@nodnol.org>
3
+ */
4
+
5
+ #include "dtrace_api.h"
6
+
7
+ RUBY_EXTERN VALUE eDtraceException;
8
+
9
+ /* :nodoc: */
10
+ VALUE dtraceaggdata_init(VALUE self)
11
+ {
12
+ dtrace_bufdata_t *data;
13
+
14
+ Data_Get_Struct(self, dtrace_bufdata_t, data);
15
+ return self;
16
+ }
17
+
18
+
19
+ VALUE dtraceaggdata_value(VALUE self)
20
+ {
21
+ dtrace_bufdata_t *bufdata;
22
+ const dtrace_aggdata_t *aggdata;
23
+ const dtrace_aggdesc_t *aggdesc;
24
+ const dtrace_recdesc_t *rec;
25
+ const char *s;
26
+ dtrace_actkind_t act = DTRACEACT_NONE;
27
+ int64_t aggid;
28
+ uint64_t normal;
29
+ caddr_t addr;
30
+ int64_t value;
31
+ VALUE v = Qnil;
32
+
33
+ Data_Get_Struct(self, dtrace_bufdata_t, bufdata);
34
+ aggdata = bufdata->dtbda_aggdata;
35
+ s = bufdata->dtbda_buffered;
36
+ rec = bufdata->dtbda_recdesc;
37
+
38
+ if (aggdata == NULL) {
39
+ rb_raise(eDtraceException, "null aggdata");
40
+ return Qnil;
41
+ }
42
+
43
+ aggdesc = aggdata->dtada_desc;
44
+
45
+ if (aggdesc == NULL) {
46
+ rb_raise(eDtraceException, "null aggdesc");
47
+ return Qnil;
48
+ }
49
+
50
+ aggid = *((int64_t *)(aggdata->dtada_data +
51
+ aggdesc->dtagd_rec[0].dtrd_offset));
52
+ if (aggid < 0) {
53
+ rb_raise(eDtraceException, "negative aggregation ID");
54
+ return Qnil;
55
+ }
56
+
57
+ act = rec->dtrd_action;
58
+
59
+ if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGKEY) {
60
+
61
+ switch (act) {
62
+ case DTRACEACT_STACK:
63
+ case DTRACEACT_USTACK:
64
+ case DTRACEACT_JSTACK:
65
+ /* todo */
66
+ break;
67
+ case DTRACEACT_USYM:
68
+ case DTRACEACT_UADDR:
69
+ case DTRACEACT_UMOD:
70
+ case DTRACEACT_SYM:
71
+ case DTRACEACT_MOD:
72
+ /* todo */
73
+ break;
74
+ default:
75
+ v = handle_bytedata((aggdata->dtada_data + rec->dtrd_offset), rec->dtrd_size);
76
+ }
77
+
78
+
79
+ } else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL) {
80
+
81
+ normal = aggdata->dtada_normal;
82
+ addr = aggdata->dtada_data + rec->dtrd_offset;
83
+
84
+ if (act == DTRACEAGG_AVG) {
85
+ uint64_t *data = (uint64_t *)addr;
86
+ value = (data[0] ? (long long)(data[1] / normal / data[0]) : 0);
87
+ } else {
88
+ value = (*((int64_t *)addr)) / normal;
89
+ }
90
+
91
+ if (act == DTRACEAGG_QUANTIZE || act == DTRACEAGG_LQUANTIZE) {
92
+ v = Qnil; // dtj_new_distribution(data, rec, jc);
93
+ } else {
94
+ switch (act) {
95
+ case DTRACEAGG_COUNT:
96
+ if (value < 0)
97
+ rb_raise(eDtraceException, "count value is negative");
98
+ v = INT2FIX(value);
99
+ break;
100
+ case DTRACEAGG_AVG:
101
+ case DTRACEAGG_MIN:
102
+ case DTRACEAGG_MAX:
103
+ case DTRACEAGG_SUM:
104
+ v = INT2FIX(value);
105
+ break;
106
+ default:
107
+ v = Qnil;
108
+ rb_raise(eDtraceException, "unexpected aggregation action: %d", act);
109
+ }
110
+ }
111
+
112
+ } else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL) {
113
+
114
+ v = Qnil;
115
+
116
+ }
117
+
118
+ return v;
119
+ }
120
+
121
+ VALUE dtraceaggdata_aggtype(VALUE self)
122
+ {
123
+ dtrace_bufdata_t *bufdata;
124
+ VALUE v;
125
+
126
+ Data_Get_Struct(self, dtrace_bufdata_t, bufdata);
127
+
128
+ if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGKEY)
129
+ v = rb_str_new2("tuple");
130
+ else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGVAL)
131
+ v = rb_str_new2("value");
132
+ else if (bufdata->dtbda_flags & DTRACE_BUFDATA_AGGLAST)
133
+ v = rb_str_new2("last");
134
+ else
135
+ v = rb_str_new2("unknown");
136
+
137
+ return v;
138
+ }
139
+
data/ext/dtrace_api.c CHANGED
@@ -10,6 +10,8 @@ VALUE cDtraceProgram;
10
10
  VALUE cDtraceProgramInfo;
11
11
  VALUE cDtraceAggData;
12
12
  VALUE cDtraceRecDesc;
13
+ VALUE cDtraceProbeData;
14
+ VALUE cDtraceBufData;
13
15
 
14
16
  VALUE eDtraceException;
15
17
 
@@ -28,6 +30,9 @@ void Init_dtrace_api() {
28
30
  rb_define_method(cDtrace, "aggregate_clear", dtrace_hdl_aggregate_clear, 0); // in dtrace_hdl.c
29
31
  rb_define_method(cDtrace, "error", dtrace_hdl_error, 0); // in dtrace_hdl.c
30
32
  rb_define_method(cDtrace, "setopt", dtrace_hdl_setopt, 2); // in dtrace_hdl.c
33
+ rb_define_method(cDtrace, "sleep", dtrace_hdl_sleep, 0); // in dtrace_hdl.c
34
+ rb_define_method(cDtrace, "work", dtrace_hdl_work, 2); // in dtrace_hdl.c
35
+ rb_define_method(cDtrace, "buf_consumer", dtrace_hdl_buf_consumer, 1); // in dtrace_hdl.c
31
36
  rb_define_alloc_func(cDtrace, dtrace_hdl_alloc);
32
37
 
33
38
  cDtraceProbe = rb_define_class("DtraceProbe", rb_cObject);
@@ -38,6 +43,15 @@ void Init_dtrace_api() {
38
43
  rb_define_method(cDtraceProbe, "func", dtraceprobe_func, 0); // in dtrace_probe.c
39
44
  rb_define_method(cDtraceProbe, "name", dtraceprobe_name, 0); // in dtrace_probe.c
40
45
 
46
+ cDtraceProbeData = rb_define_class("DtraceProbeData", rb_cObject);
47
+ rb_define_method(cDtraceProbeData, "initialize", dtraceprobedata_init, 0); // in dtrace_probedata.c
48
+ rb_define_method(cDtraceProbeData, "probedesc", dtraceprobedata_probedesc, 0); // in dtrace_probedata.c
49
+ rb_define_method(cDtraceProbeData, "each_record", dtraceprobedata_each_record, 0); // in dtrace_probedata.c
50
+
51
+ cDtraceBufData = rb_define_class("DtraceBufData", rb_cObject);
52
+ rb_define_method(cDtraceBufData, "initialize", dtracebufdata_init, 0); // in dtrace_bufdata.c
53
+ rb_define_method(cDtraceBufData, "record", dtracebufdata_record, 0); // in dtrace_bufdata.c
54
+
41
55
  cDtraceProgram = rb_define_class("DtraceProgram", rb_cObject);
42
56
  rb_define_method(cDtraceProgram, "initialize", dtraceprogram_init, 0); // in dtrace_program.c
43
57
  rb_define_method(cDtraceProgram, "execute", dtraceprogram_exec, 0); // in dtrace_program.c
@@ -51,18 +65,12 @@ void Init_dtrace_api() {
51
65
  rb_define_method(cDtraceProgramInfo, "speculations_count", dtraceprograminfo_speculations_count, 0); // in dtrace_programinfo.c
52
66
 
53
67
  cDtraceAggData = rb_define_class("DtraceAggData", rb_cObject);
54
- rb_define_method(cDtraceAggData, "initialize", dtraceaggdata_init, 0); // in dtrace_aggregate.c
55
- rb_define_method(cDtraceAggData, "desc", dtraceaggdata_desc, 0); // in dtrace_aggregate.c
56
- rb_define_method(cDtraceAggData, "value", dtraceaggdata_value, 0); // in dtrace_aggregate.c
57
- rb_define_method(cDtraceAggData, "size", dtraceaggdata_size, 0); // in dtrace_aggregate.c
58
- rb_define_method(cDtraceAggData, "each_record", dtraceaggdata_each_record, 0); // in dtrace_aggregate.c
59
- rb_define_method(cDtraceAggData, "num_records", dtraceaggdata_num_records, 0); // in dtrace_aggregate.c
60
- rb_define_method(cDtraceAggData, "[]", dtraceaggdata_record, 1); // in dtrace_aggregate.c
61
- rb_define_method(cDtraceAggData, "probe", dtraceaggdata_probe, 0); // in dtrace_aggregate.c
68
+ rb_define_method(cDtraceAggData, "initialize", dtraceaggdata_init, 0); // in dtrace_aggdata.c
69
+ rb_define_method(cDtraceAggData, "value", dtraceaggdata_value, 0); // in dtrace_aggdata.c
70
+ rb_define_method(cDtraceAggData, "aggtype", dtraceaggdata_aggtype, 0); // in dtrace_aggdata.c
62
71
 
63
72
  cDtraceRecDesc = rb_define_class("DtraceRecDesc", rb_cObject);
64
73
  rb_define_method(cDtraceRecDesc, "initialize", dtracerecdesc_init, 0); // in dtrace_recdesc.c
65
- rb_define_method(cDtraceRecDesc, "data", dtracerecdesc_data, 0); // in dtrace_recdesc.c
66
74
 
67
75
  eDtraceException = rb_define_class("DtraceException", rb_eStandardError);
68
76
  }
data/ext/dtrace_api.h CHANGED
@@ -8,14 +8,11 @@
8
8
  #include "/usr/include/dtrace.h"
9
9
  #include "ruby.h"
10
10
 
11
+ VALUE handle_bytedata(caddr_t addr, uint32_t nbytes);
12
+
11
13
  VALUE dtraceaggdata_init(VALUE self);
12
- VALUE dtraceaggdata_desc(VALUE self);
13
14
  VALUE dtraceaggdata_value(VALUE self);
14
- VALUE dtraceaggdata_size(VALUE self);
15
- VALUE dtraceaggdata_each_record(VALUE self);
16
- VALUE dtraceaggdata_num_records(VALUE self);
17
- VALUE dtraceaggdata_record(VALUE self, VALUE index);
18
- VALUE dtraceaggdata_probe(VALUE self);
15
+ VALUE dtraceaggdata_aggtype(VALUE self);
19
16
 
20
17
  void dtrace_hdl_free (void *handle);
21
18
  VALUE dtrace_hdl_alloc(VALUE klass);
@@ -31,6 +28,11 @@ VALUE dtrace_hdl_aggregate_print(VALUE self);
31
28
  VALUE dtrace_hdl_aggregate_snap(VALUE self);
32
29
  VALUE dtrace_hdl_aggregate_clear(VALUE self);
33
30
  VALUE dtrace_hdl_error(VALUE self);
31
+ VALUE dtrace_hdl_sleep(VALUE self);
32
+ VALUE dtrace_hdl_work(VALUE self,
33
+ VALUE probe_consumer_proc,
34
+ VALUE rec_consumer_proc);
35
+ VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer_proc);
34
36
 
35
37
  VALUE dtraceprobe_init(VALUE self);
36
38
  VALUE dtraceprobe_probe_id(VALUE self);
@@ -39,6 +41,13 @@ VALUE dtraceprobe_mod(VALUE self);
39
41
  VALUE dtraceprobe_func(VALUE self);
40
42
  VALUE dtraceprobe_name(VALUE self);
41
43
 
44
+ VALUE dtraceprobedata_init(VALUE self);
45
+ VALUE dtraceprobedata_probedesc(VALUE self);
46
+ VALUE dtraceprobedata_each_record(VALUE self);
47
+
48
+ VALUE dtracebufdata_init(VALUE self);
49
+ VALUE dtracebufdata_record(VALUE self);
50
+
42
51
  VALUE dtraceprogram_init(VALUE self);
43
52
  VALUE dtraceprogram_exec(VALUE self);
44
53
  VALUE dtraceprogram_info(VALUE self);
@@ -50,4 +59,3 @@ VALUE dtraceprograminfo_matches_count(VALUE self);
50
59
  VALUE dtraceprograminfo_speculations_count(VALUE self);
51
60
 
52
61
  VALUE dtracerecdesc_init(VALUE self);
53
- VALUE dtracerecdesc_data(VALUE self);
@@ -0,0 +1,91 @@
1
+ /* Ruby-Dtrace
2
+ * (c) 2007 Chris Andrews <chris@nodnol.org>
3
+ */
4
+
5
+ #include "dtrace_api.h"
6
+
7
+ RUBY_EXTERN VALUE eDtraceException;
8
+ RUBY_EXTERN VALUE cDtraceAggData;
9
+ RUBY_EXTERN VALUE cDtraceRecDesc;
10
+
11
+ /* :nodoc: */
12
+ VALUE dtracebufdata_init(VALUE self)
13
+ {
14
+ dtrace_bufdata_t *data;
15
+
16
+ Data_Get_Struct(self, dtrace_bufdata_t, data);
17
+ return self;
18
+ }
19
+
20
+ VALUE dtracebufdata_record(VALUE self)
21
+ {
22
+ dtrace_bufdata_t *bufdata;
23
+ const dtrace_recdesc_t *rec;
24
+ dtrace_actkind_t act = DTRACEACT_NONE;
25
+ const char *s;
26
+ VALUE v = Qnil;
27
+ VALUE dtracerecord;
28
+ VALUE dtraceaggdata;
29
+ VALUE dtracerecdesc;
30
+
31
+ Data_Get_Struct(self, dtrace_bufdata_t, bufdata);
32
+
33
+ if (bufdata->dtbda_aggdata) {
34
+ dtraceaggdata = Data_Wrap_Struct(cDtraceAggData, 0, NULL, (dtrace_bufdata_t *)bufdata);
35
+ return dtraceaggdata;
36
+ }
37
+
38
+ s = bufdata->dtbda_buffered;
39
+ if (s == NULL) {
40
+ return Qnil;
41
+ }
42
+
43
+ rec = bufdata->dtbda_recdesc;
44
+ if (rec) {
45
+ act = rec->dtrd_action;
46
+ }
47
+
48
+ switch (act) {
49
+ case DTRACEACT_DIFEXPR:
50
+ /* trace() action */
51
+ break;
52
+ case DTRACEACT_PRINTF:
53
+ /*
54
+ * Only the formatted string was not available to dtj_chewrec(),
55
+ * so we attach that now.
56
+ */
57
+ v = rb_str_new2(s);
58
+ break;
59
+ case DTRACEACT_STACK:
60
+ case DTRACEACT_USTACK:
61
+ case DTRACEACT_JSTACK:
62
+ /* stand-alone stack(), ustack(), or jstack() action */
63
+ v = rb_str_new2(s);
64
+ break;
65
+ case DTRACEACT_USYM:
66
+ case DTRACEACT_UADDR:
67
+ case DTRACEACT_UMOD:
68
+ case DTRACEACT_SYM:
69
+ case DTRACEACT_MOD:
70
+ v = rb_str_new2(s);
71
+ break;
72
+ case DTRACEACT_PRINTA:
73
+ v = rb_str_new2(s);
74
+ break;
75
+ default:
76
+ /*
77
+ * The record handle defers nothing else to this
78
+ * bufhandler.
79
+ */
80
+ break;
81
+ }
82
+
83
+ if (!NIL_P(v)) {
84
+ dtracerecord = rb_class_new_instance(0, NULL, rb_path2class("DtraceRecord"));
85
+ rb_iv_set(dtracerecord, "@value", v);
86
+ return (dtracerecord);
87
+ }
88
+ else {
89
+ return Qnil;
90
+ }
91
+ }
data/ext/dtrace_hdl.c CHANGED
@@ -8,6 +8,9 @@ RUBY_EXTERN VALUE eDtraceException;
8
8
  RUBY_EXTERN VALUE cDtraceProbe;
9
9
  RUBY_EXTERN VALUE cDtraceProgram;
10
10
  RUBY_EXTERN VALUE cDtraceAggData;
11
+ RUBY_EXTERN VALUE cDtraceRecDesc;
12
+ RUBY_EXTERN VALUE cDtraceProbeData;
13
+ RUBY_EXTERN VALUE cDtraceBufData;
11
14
 
12
15
  void dtrace_hdl_free (void *handle)
13
16
  {
@@ -278,3 +281,101 @@ VALUE dtrace_hdl_error(VALUE self)
278
281
  return rb_str_new2(error_string);
279
282
  }
280
283
 
284
+ /*
285
+ * Sleep until we need to wake up to honour D options controlling
286
+ * consumption rates.
287
+ */
288
+ VALUE dtrace_hdl_sleep(VALUE self)
289
+ {
290
+ dtrace_hdl_t *handle;
291
+
292
+ Data_Get_Struct(self, dtrace_hdl_t, handle);
293
+ dtrace_sleep(handle);
294
+ return Qnil;
295
+ }
296
+
297
+ typedef struct dtrace_work_handlers {
298
+ VALUE probe;
299
+ VALUE rec;
300
+ } dtrace_work_handlers_t;
301
+
302
+ static int _probe_consumer(const dtrace_probedata_t *data, void *arg)
303
+ {
304
+ VALUE proc;
305
+ dtrace_work_handlers_t handlers;
306
+ VALUE probedata;
307
+
308
+ handlers = *(dtrace_work_handlers_t *) arg;
309
+ proc = handlers.probe;
310
+
311
+ probedata = Data_Wrap_Struct(cDtraceProbeData, 0, NULL, (dtrace_probedata_t *)data);
312
+ rb_funcall(proc, rb_intern("call"), 1, probedata);
313
+
314
+ return (DTRACE_CONSUME_THIS);
315
+ }
316
+
317
+ static int _rec_consumer(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
318
+ {
319
+ VALUE proc;
320
+ dtrace_work_handlers_t handlers;
321
+ VALUE recdesc;
322
+
323
+ handlers = *(dtrace_work_handlers_t *) arg;
324
+ proc = handlers.rec;
325
+
326
+ recdesc = Data_Wrap_Struct(cDtraceRecDesc, 0, NULL, (dtrace_recdesc_t *)rec);
327
+ rb_funcall(proc, rb_intern("call"), 1, recdesc);
328
+
329
+ return (DTRACE_CONSUME_THIS);
330
+ }
331
+
332
+ static int _buf_consumer(const dtrace_bufdata_t *bufdata, void *arg)
333
+ {
334
+ VALUE proc;
335
+ VALUE dtracebufdata;
336
+
337
+ proc = (VALUE)arg;
338
+
339
+ dtracebufdata = Data_Wrap_Struct(cDtraceBufData, 0, NULL, (dtrace_bufdata_t *)bufdata);
340
+ rb_funcall(proc, rb_intern("call"), 1, dtracebufdata);
341
+
342
+ return (DTRACE_HANDLE_OK);
343
+ }
344
+
345
+ /*
346
+ * Process any data waiting from the D program.
347
+ */
348
+ VALUE dtrace_hdl_work(VALUE self,
349
+ VALUE probe_consumer_proc,
350
+ VALUE rec_consumer_proc)
351
+ {
352
+ dtrace_hdl_t *handle;
353
+ dtrace_workstatus_t status;
354
+ dtrace_work_handlers_t handlers;
355
+
356
+ Data_Get_Struct(self, dtrace_hdl_t, handle);
357
+
358
+ /* fill out the handlers struct */
359
+ handlers.probe = probe_consumer_proc;
360
+ handlers.rec = rec_consumer_proc;
361
+
362
+ status = dtrace_work(handle, NULL, _probe_consumer, _rec_consumer, &handlers);
363
+
364
+ return INT2FIX(status);
365
+ }
366
+
367
+ /*
368
+ * Set up the buffered output handler for this handle.
369
+ */
370
+ VALUE dtrace_hdl_buf_consumer(VALUE self, VALUE buf_consumer)
371
+ {
372
+ dtrace_hdl_t *handle;
373
+ Data_Get_Struct(self, dtrace_hdl_t, handle);
374
+
375
+ /* attach the buffered output handler */
376
+ if (dtrace_handle_buffered(handle, &_buf_consumer, (void *)buf_consumer) == -1) {
377
+ rb_raise(eDtraceException, "failed to establish buffered handler");
378
+ }
379
+
380
+ return Qnil;
381
+ }