ruby-dtrace 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
+