ruby-dtrace 0.0.2 → 0.0.3

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 CHANGED
@@ -1,3 +1,12 @@
1
+ == 0.0.3 / 2008-01-06
2
+
3
+ * Add a DtraceData class which consumers return, containing
4
+ the data returned from each probe firing, rather than
5
+ returning the raw records directly from DTrace.
6
+ * Provide access to probe, CPU and flow information.
7
+ * Allow creation and grabbing of processes.
8
+ * Add an example script: a port of scsi.d.
9
+
1
10
  == 0.0.2 / 2007-12-07
2
11
 
3
12
  * Implement the dtrace_work-based API
data/Manifest.txt CHANGED
@@ -2,6 +2,7 @@ History.txt
2
2
  Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
+ examples/scsi.rb
5
6
  ext/dtrace_aggdata.c
6
7
  ext/dtrace_api.c
7
8
  ext/dtrace_api.h
@@ -9,6 +10,7 @@ ext/dtrace_bufdata.c
9
10
  ext/dtrace_hdl.c
10
11
  ext/dtrace_probe.c
11
12
  ext/dtrace_probedata.c
13
+ ext/dtrace_process.c
12
14
  ext/dtrace_program.c
13
15
  ext/dtrace_programinfo.c
14
16
  ext/dtrace_recdesc.c
@@ -16,10 +18,14 @@ ext/dtrace_util.c
16
18
  ext/extconf.rb
17
19
  lib/dtrace.rb
18
20
  lib/dtraceaggregate.rb
21
+ lib/dtraceaggregateset.rb
19
22
  lib/dtraceconsumer.rb
23
+ lib/dtracedata.rb
24
+ lib/dtraceprintfrecord.rb
20
25
  lib/dtraceprobe.rb
21
26
  lib/dtraceprobedata.rb
22
27
  lib/dtracerecord.rb
28
+ lib/dtracestackrecord.rb
23
29
  plugin/dtrace/README
24
30
  plugin/dtrace/Rakefile
25
31
  plugin/dtrace/bin/dtracer.rb
@@ -34,4 +40,8 @@ plugin/dtrace/tasks/dtrace.rake
34
40
  plugin/dtrace/test/dtrace_test.rb
35
41
  plugin/dtrace/views/dtrace/_report.rhtml
36
42
  test/test_dtrace.rb
37
- test/test_dtrace_workapi.rb
43
+ test/test_dtrace_aggregates.rb
44
+ test/test_dtrace_processes.rb
45
+ test/test_dtrace_profile.rb
46
+ test/test_dtrace_repeat.rb
47
+ test/test_dtrace_rubyprobe.rb
data/README.txt CHANGED
@@ -8,24 +8,23 @@ use it with the probes found in the Joyent and Apple builds of Ruby.
8
8
  * Probe metadata
9
9
  * Run D programs
10
10
  * Access aggregates
11
+ * Consume output from D programs
11
12
 
12
13
  == SYNOPSIS
13
14
 
14
- t = Dtrace.new
15
- dprog = "ruby*:::function-entry{ @[copyinstr(arg1)] = count(); }"
16
- prog = t.compile dprog
15
+ t = Dtrace.new
16
+ progtext = 'ruby$1:::function-entry{ @a[strjoin(strjoin(copyinstr(arg0),"."),copyinstr(arg1))] = count(); } END { printa(@a); }'
17
+ prog = t.compile progtext
17
18
  prog.execute
19
+
18
20
  t.go
19
21
 
20
22
  [...]
21
-
22
- t.stop
23
- t.aggregate_snap
24
- t.each_aggregate do |agg|
25
- (0..(agg.num_records - 1)).each do |i|
26
- rec = agg[i]
27
- end
28
- end
23
+
24
+ c = DtraceConsumer.new(t)
25
+ c.consume_once do |rec|
26
+ # handle records
27
+ end
29
28
 
30
29
  == REQUIREMENTS
31
30
 
data/examples/scsi.rb ADDED
@@ -0,0 +1,442 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'dtrace'
4
+ require 'getoptlong'
5
+
6
+ # scsi.rb: part of ruby-dtrace, (c) Chris Andrews, 2007
7
+ #
8
+ # This is a ruby reimplementation of Chris Gerhard's "scsi.d" script,
9
+ # obtained from here:
10
+ # http://blogs.sun.com/chrisg/resource/scsi_d/scsi.d-1.12
11
+ #
12
+ # It's meant as an example of how you might use ruby to keep the D
13
+ # script simple. For actually debugging SCSI, scsi.d is probably a
14
+ # better bet!
15
+
16
+ class ScsiCdb
17
+ attr_reader :op, :len, :control, :lba, :cdblen
18
+
19
+ def initialize(group, cdb_bytes)
20
+ @bytes = cdb_bytes
21
+ @group = group
22
+ parse
23
+ end
24
+
25
+ def raw
26
+ @bytes.slice(0, @cdblen).inject('') {|string, b| string + sprintf('%2.2x', b) }
27
+ end
28
+
29
+ def parse
30
+
31
+ case @group
32
+ when 0
33
+ @lba = int32([0, @bytes[1] & 0x1f, @bytes[2], @bytes[3]])
34
+ @lbalen = 6;
35
+ @len = int8(@bytes[4])
36
+ @control = @bytes[5]
37
+ @sa = 0
38
+ @cdblen = 6
39
+
40
+ when 1
41
+ @lba = int32(@bytes[2..5])
42
+ @lbalen = 8
43
+ @len = int16(@bytes[7..8])
44
+ @control = @bytes[9]
45
+ @sa = 0
46
+ @cdblen = 10
47
+
48
+ when 2
49
+ @lba = int32(@bytes[2..5])
50
+ @lbalen = 8
51
+ @len = int16(@bytes[7..8])
52
+ @control = @bytes[9]
53
+ @sa = 0
54
+ @cdblen = 10
55
+
56
+ when 3
57
+ @lba = int64(@bytes[12..19])
58
+ @lbalen = 16;
59
+ @len = int32(@bytes[28..31])
60
+ @control = @bytes[1]
61
+ @sa = int16(@bytes[8..9])
62
+ @cdblen = 32
63
+
64
+ when 4
65
+ @lba = int64(@bytes[2..9])
66
+ @lbalen = 16
67
+ @len = int32(@bytes[10.13])
68
+ @control = @bytes[15]
69
+ @sa = 0
70
+ @cdblen = 16
71
+
72
+ when 5
73
+ @lba = int32(@bytes[2..5])
74
+ @lbalen = 8;
75
+ @len = int32(@bytes[6..9])
76
+ @control = @bytes[11]
77
+ @sa = 0
78
+ @cdblen = 12
79
+
80
+ when 6 .. 7
81
+ @lba = 0
82
+ @lbalen = 0
83
+ @len = 0
84
+ @control = 0
85
+ @sa = 0
86
+
87
+ end
88
+
89
+ @op = scsi_op(@bytes[0], @sa)
90
+ end
91
+
92
+ private
93
+ def int8(byte)
94
+ return byte & 0x0ff;
95
+ end
96
+
97
+ def int16(bytes)
98
+ return (int8(bytes[0]) << 8) + int8(bytes[1])
99
+ end
100
+
101
+ def int32(bytes)
102
+ return (int16(bytes[0..1]) << 16) + int16(bytes[2..3])
103
+ end
104
+
105
+ def int64(bytes)
106
+ return (int32(bytes[0..3]) << 32) + int32(bytes[4..7])
107
+ end
108
+
109
+ def scsi_op(code, code2)
110
+ scsi_ops = {
111
+ 0x000 => "TEST_UNIT_READY",
112
+ 0x001 => "REZERO_UNIT_or_REWIND",
113
+ 0x003 => "REQUEST_SENSE",
114
+ 0x004 => "FORMAT_UNIT",
115
+ 0x007 => "REASSIGN_BLOCKS",
116
+ 0x008 => "READ(6)",
117
+ 0x00a => "WRITE(6)",
118
+ 0x00b => "SEEK(6)",
119
+ 0x012 => "INQUIRY",
120
+ 0x015 => "MODE_SELECT(6)",
121
+ 0x016 => "RESERVE(6)",
122
+ 0x017 => "RELEASE(6)",
123
+ 0x018 => "COPY",
124
+ 0x019 => "ERASE(6)",
125
+ 0x01a => "MODE_SENSE(6)",
126
+ 0x01b => "START_STOP_UNIT",
127
+ 0x01c => "RECIEVE_DIAGNOSTIC_RESULTS",
128
+ 0x01d => "SEND_DIAGNOSTIC",
129
+ 0x01e => "PREVENT_ALLOW_MEDIUM_REMOVAL",
130
+ 0x025 => "READ_CAPACITY(10)",
131
+ 0x028 => "READ(10)",
132
+ 0x02a => "WRITE(10)",
133
+ 0x02b => "SEEK(10)_or_LOCATE(10)",
134
+ 0x02e => "WRITE_AND_VERIFY(10)",
135
+ 0x02f => "VERIFY(10)",
136
+ 0x030 => "SEARCH_DATA_HIGH",
137
+ 0x031 => "SEARCH_DATA_EQUAL",
138
+ 0x032 => "SEARCH_DATA_LOW",
139
+ 0x033 => "SET_LIMITS(10)",
140
+ 0x034 => "PRE-FETCH(10)",
141
+ 0x035 => "SYNCHRONIZE_CACHE(10)",
142
+ 0x036 => "LOCK_UNLOCK_CACHE(10)",
143
+ 0x037 => "READ_DEFECT_DATA(10)",
144
+ 0x039 => "COMPARE",
145
+ 0x03a => "COPY_AND_WRITE",
146
+ 0x03b => "WRITE_BUFFER",
147
+ 0x03c => "READ_BUFFER",
148
+ 0x03e => "READ_LONG",
149
+ 0x03f => "WRITE_LONG",
150
+ 0x040 => "CHANGE_DEFINITION",
151
+ 0x041 => "WRITE_SAME(10)",
152
+ 0x04c => "LOG_SELECT",
153
+ 0x04d => "LOG_SENSE",
154
+ 0x050 => "XDWRITE(10)",
155
+ 0x051 => "XPWRITE(10)",
156
+ 0x052 => "XDREAD(10)",
157
+ 0x053 => "XDWRITEREAD(10)",
158
+ 0x055 => "MODE_SELECT(10)",
159
+ 0x056 => "RESERVE(10)",
160
+ 0x057 => "RELEASE(10)",
161
+ 0x05a => "MODE_SENSE(10)",
162
+ 0x05e => "PERSISTENT_RESERVE_IN",
163
+ 0x05f => "PERSISTENT_RESERVE_OUT",
164
+ 0x07f => "Variable_Length_CDB",
165
+ 0x080 => "XDWRITE_EXTENDED(16)",
166
+ 0x081 => "REBUILD(16)",
167
+ 0x082 => "REGENERATE(16)",
168
+ 0x083 => "EXTENDED_COPY",
169
+ 0x086 => "ACCESS_CONTROL_IN",
170
+ 0x087 => "ACCESS_CONTROL_OUT",
171
+ 0x088 => "READ(16)",
172
+ 0x08a => "WRITE(16)",
173
+ 0x08c => "READ_ATTRIBUTES",
174
+ 0x08d => "WRITE_ATTRIBUTES",
175
+ 0x08e => "WRITE_AND_VERIFY(16)",
176
+ 0x08f => "VERIFY(16)",
177
+ 0x090 => "PRE-FETCH(16)",
178
+ 0x091 => "SYNCHRONIZE_CACHE(16)",
179
+ 0x092 => "LOCK_UNLOCK_CACHE(16)_or_LOCATE(16)",
180
+ 0x093 => "WRITE_SAME(16)_or_ERASE(16)",
181
+ 0x09e => "SERVICE_IN_or_READ_CAPACITY(16)",
182
+ 0x0a0 => "REPORT_LUNS",
183
+ 0x0a3 => "MAINTENANCE_IN_or_REPORT_TARGET_PORT_GROUPS",
184
+ 0x0a4 => "MAINTENANCE_OUT_or_SET_TARGET_PORT_GROUPS",
185
+ 0x0a7 => "MOVE_MEDIUM",
186
+ 0x0a8 => "READ(12)",
187
+ 0x0aa => "WRITE(12)",
188
+ 0x0ae => "WRITE_AND_VERIFY(12)",
189
+ 0x0af => "VERIFY(12)",
190
+ 0x0b3 => "SET_LIMITS(12)",
191
+ 0x0b4 => "READ_ELEMENT_STATUS",
192
+ 0x0b7 => "READ_DEFECT_DATA(12)",
193
+ 0x0ba => "REDUNDANCY_GROUP_IN",
194
+ 0x0bb => "REDUNDANCY_GROUP_OUT",
195
+ 0x0bc => "SPARE_IN",
196
+ 0x0bd => "SPARE_OUT",
197
+ 0x0be => "VOLUME_SET_IN",
198
+ 0x0bf => "VOLUME_SET_OUT",
199
+ 0x0d0 => "EXPLICIT_LUN_FAILOVER",
200
+ 0x0f1 => "STOREDGE_CONTROLLER"
201
+ }
202
+
203
+ variable_length_ops = {
204
+ 0x3 => "XDREAD(32)",
205
+ 0x4 => "XDWRITE(32)",
206
+ 0x6 => "XPWRITE(32)",
207
+ 0x7 => "XDWRITEREAD(32)",
208
+ 0x9 => "READ(32)",
209
+ 0xb => "WRITE(32)",
210
+ 0xa => "VERIFY(32)",
211
+ 0xc => "WRITE_AND_VERIFY(32)"
212
+ }
213
+
214
+ op = scsi_ops[code]
215
+ if op == 'Variable_Length_CDB'
216
+ return variable_length_ops[code2]
217
+ else
218
+ return op
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ def scsi_reason(code)
225
+ scsi_reasons = {
226
+ 0 => "COMPLETED",
227
+ 1 => "INCOMPLETE",
228
+ 2 => "DMA_ERR",
229
+ 3 => "TRAN_ERR",
230
+ 4 => "RESET",
231
+ 5 => "ABORTED",
232
+ 6 => "TIMEOUT",
233
+ 7 => "DATA_OVERRUN",
234
+ 8 => "COMMAND_OVERRUN",
235
+ 9 => "STATUS_OVERRUN",
236
+ 10 => "Bad_Message",
237
+ 11 => "No_Message_Out",
238
+ 12 => "XID_Failed",
239
+ 13 => "IDE_Failed",
240
+ 14 => "Abort_Failed",
241
+ 15 => "Reject_Failed",
242
+ 16 => "Nop_Failed",
243
+ 17 => "Message_Parity_Error_Failed",
244
+ 18 => "Bus_Device_Reset_Failed",
245
+ 19 => "Identify_Message_Rejected",
246
+ 20 => "Unexpected_Bus_free",
247
+ 21 => "Tag_Rejected",
248
+ 22 => "TERMINATED",
249
+ 24 => "Device_Gone"
250
+ }
251
+ return scsi_reasons[code]
252
+ end
253
+
254
+ timeout = 0
255
+ opts = GetoptLong.new([ '-T', GetoptLong::REQUIRED_ARGUMENT ])
256
+ opts.each do |opt, arg|
257
+ if opt == '-T'
258
+ timeout = arg
259
+ end
260
+ end
261
+
262
+ devname = ARGV.shift
263
+ devinst = ARGV.shift
264
+
265
+ if devname && devinst
266
+ matchdev = "/this->devname == \"#{devname}\" && this->devinst == #{devinst}/"
267
+ elsif devname
268
+ matchdev = "/this->devname == \"#{devname}\"/"
269
+ else
270
+ matchdev = ""
271
+ end
272
+
273
+ progtext =<<"EOD"
274
+
275
+ struct scsi_cdb {
276
+ uint8_t bytes[32];
277
+ };
278
+
279
+ BEGIN
280
+ {
281
+ script_start_time = timestamp;
282
+ timeout = #{timeout};
283
+ end_time = timestamp + (timeout * 1000000000);
284
+ }
285
+
286
+ fbt:scsi:scsi_transport:entry,
287
+ fbt:scsi:scsi_destroy_pkt:entry
288
+ /timeout != 0 && end_time < timestamp/
289
+ {
290
+ exit(0);
291
+ }
292
+
293
+ fbt:scsi:scsi_transport:entry,
294
+ fbt:scsi:scsi_destroy_pkt:entry
295
+ {
296
+ this->pkt = (struct scsi_pkt *)arg0;
297
+ this->scb = (uchar_t *)this->pkt->pkt_scbp;
298
+
299
+ this->devinfo = ((struct dev_info *)((this->pkt->pkt_address.a_hba_tran)->tran_hba_dip));
300
+ this->devname = stringof(`devnamesp[this->devinfo->devi_major].dn_name);
301
+ this->devinst = this->devinfo->devi_instance;
302
+
303
+ relevant[this->scb] = 0;
304
+ }
305
+
306
+ fbt:scsi:scsi_transport:entry,
307
+ fbt:scsi:scsi_destroy_pkt:entry
308
+ #{matchdev}
309
+ {
310
+ relevant[this->scb] = 1;
311
+ }
312
+
313
+ fbt:scsi:scsi_transport:entry
314
+ /relevant[this->scb] == 1/
315
+ {
316
+ start_time[this->scb] = timestamp;
317
+ this->dir = 1;
318
+ }
319
+
320
+ fbt:scsi:scsi_destroy_pkt:entry
321
+ /relevant[this->scb] == 1/
322
+ {
323
+ req_time[this->scb] = start_time[this->scb] != 0 ?
324
+ (timestamp - start_time[this->scb])/1000 : 0;
325
+ start_time[this->scb] = 0;
326
+ this->dir = 0;
327
+ }
328
+
329
+ fbt:scsi:scsi_transport:entry,
330
+ fbt:scsi:scsi_destroy_pkt:entry
331
+ /relevant[this->scb] == 1/
332
+ {
333
+ this->cdb = (uchar_t *)this->pkt->pkt_cdbp;
334
+ this->group = ((this->cdb[0] & 0xe0) >> 5);
335
+
336
+ /* timestamp */
337
+ trace((timestamp - script_start_time)/1000000000);
338
+ trace((timestamp - script_start_time)%1000000000);
339
+
340
+ /* devname, devinst */
341
+ trace(this->devname);
342
+ trace(this->devinst);
343
+
344
+ /* scsi cdb */
345
+ trace(this->cdb);
346
+ trace(this->group);
347
+ trace(*(struct scsi_cdb *)(this->cdb));
348
+
349
+ /* command or response? */
350
+ trace(this->dir);
351
+
352
+ /* target and LUN */
353
+ trace(this->pkt->pkt_address.a_target);
354
+ trace(this->pkt->pkt_address.a_lun);
355
+
356
+ /* timeout */
357
+ trace(this->pkt->pkt_time);
358
+
359
+ /* executable and pid, for commands */
360
+ trace(execname);
361
+ trace(pid);
362
+
363
+ /* reason and state, for responses */
364
+ trace(this->pkt->pkt_reason);
365
+ trace(this->pkt->pkt_state);
366
+
367
+ /* elapsed time for this command/response */
368
+ trace(req_time[this->scb]);
369
+ req_time[this->scb] = 0;
370
+
371
+ relevant[this->scb] = 0;
372
+ }
373
+
374
+ EOD
375
+ #`
376
+
377
+ t = Dtrace.new
378
+ t.setopt("bufsize", "4m")
379
+ prog = t.compile progtext
380
+ prog.execute
381
+ t.go
382
+
383
+ begin
384
+ c = DtraceConsumer.new(t)
385
+
386
+ c.consume do |d|
387
+ records = d.data
388
+
389
+ # D exit at timeout
390
+ if records.length == 1 && records[0].value == 0
391
+ exit 0
392
+ end
393
+
394
+ # first two elements are timestamp
395
+ t = sprintf("%05.5d.%09.9d", records.shift.value, records.shift.value)
396
+
397
+ # next two elements are devname/devinst
398
+ dev = sprintf('%s%d', records.shift.value, records.shift.value)
399
+
400
+ # next is CBDP, group, then 32 bytes of CDB
401
+ cdbp = records.shift.value
402
+ group = records.shift.value
403
+ cdb_bytes = records.shift.value
404
+
405
+ # then dir flag
406
+ dir = (records.shift.value == 1) ? '->' : '<-'
407
+
408
+ # address
409
+ address_target = records.shift.value
410
+ address_lun = records.shift.value
411
+
412
+ # timeout
413
+ timeout = records.shift.value
414
+
415
+ # execname and pid
416
+ execname = records.shift.value
417
+ pid = records.shift.value
418
+
419
+ # reason, state, request time
420
+ reason = records.shift.value
421
+ state = records.shift.value
422
+ req_time = records.shift.value
423
+
424
+ # parse the CDB
425
+ cdb = ScsiCdb.new(group, cdb_bytes)
426
+
427
+ printf "%s %s:%s 0x%2.2x %9s address %2.2d:%2.2d, lba 0x%08x, len 0x%6.6x, control 0x%2.2x timeout %d CDBP 0x%x",
428
+ t, dev, dir, cdb_bytes[0], cdb.op, address_target, address_lun,
429
+ cdb.lba, cdb.len, cdb.control, timeout, cdbp, execname, pid
430
+
431
+ case dir
432
+ when '->'
433
+ printf " %s(%d) cdb(%d) %s\n", execname, pid, cdb.cdblen, cdb.raw
434
+ when '<-'
435
+ printf ", reason 0x%x (%s) state 0x%x Time %dus\n", reason, scsi_reason(reason), state, req_time
436
+ end
437
+ end
438
+
439
+ rescue Interrupt => e
440
+ exit
441
+ end
442
+