chrisa-ruby-dtrace 0.2.0

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 (88) hide show
  1. data/History.txt +34 -0
  2. data/Manifest.txt +58 -0
  3. data/README.txt +88 -0
  4. data/Rakefile +73 -0
  5. data/examples/scsi.rb +442 -0
  6. data/ext/dof/constants.c +49 -0
  7. data/ext/dof/dof.h +55 -0
  8. data/ext/dof/dof_api.c +57 -0
  9. data/ext/dof/dof_helper.c +82 -0
  10. data/ext/dof/extconf.rb +4 -0
  11. data/ext/dof/file.c +56 -0
  12. data/ext/dof/generator.c +9 -0
  13. data/ext/dof/header.c +80 -0
  14. data/ext/dof/parser.c +415 -0
  15. data/ext/dof/parser.h +10 -0
  16. data/ext/dof/section.c +302 -0
  17. data/ext/dtrace_aggdata.c +142 -0
  18. data/ext/dtrace_api.c +119 -0
  19. data/ext/dtrace_api.h +150 -0
  20. data/ext/dtrace_bufdata.c +139 -0
  21. data/ext/dtrace_dropdata.c +131 -0
  22. data/ext/dtrace_errdata.c +110 -0
  23. data/ext/dtrace_hdl.c +577 -0
  24. data/ext/dtrace_probedata.c +267 -0
  25. data/ext/dtrace_probedesc.c +78 -0
  26. data/ext/dtrace_process.c +37 -0
  27. data/ext/dtrace_program.c +62 -0
  28. data/ext/dtrace_programinfo.c +60 -0
  29. data/ext/dtrace_recdesc.c +46 -0
  30. data/ext/dtrace_util.c +92 -0
  31. data/ext/extconf.rb +28 -0
  32. data/ext/stubs.txt +78 -0
  33. data/lib/dtrace/aggregate.rb +40 -0
  34. data/lib/dtrace/aggregateset.rb +19 -0
  35. data/lib/dtrace/consumer.rb +174 -0
  36. data/lib/dtrace/data.rb +82 -0
  37. data/lib/dtrace/dof/file.rb +63 -0
  38. data/lib/dtrace/dof/section/strtab.rb +21 -0
  39. data/lib/dtrace/dof/section.rb +69 -0
  40. data/lib/dtrace/dof.rb +8 -0
  41. data/lib/dtrace/printfrecord.rb +10 -0
  42. data/lib/dtrace/probe.rb +46 -0
  43. data/lib/dtrace/probedata.rb +23 -0
  44. data/lib/dtrace/probedesc.rb +15 -0
  45. data/lib/dtrace/provider/probedef.rb +24 -0
  46. data/lib/dtrace/provider.rb +231 -0
  47. data/lib/dtrace/record.rb +11 -0
  48. data/lib/dtrace/stackrecord.rb +31 -0
  49. data/lib/dtrace/tracer.rb +35 -0
  50. data/lib/dtrace.rb +74 -0
  51. data/lib/dtraceconsumer.rb +9 -0
  52. data/plugin/dtrace/README +81 -0
  53. data/plugin/dtrace/Rakefile +22 -0
  54. data/plugin/dtrace/bin/dtracer.rb +29 -0
  55. data/plugin/dtrace/init.rb +7 -0
  56. data/plugin/dtrace/lib/dtrace_helper.rb +2 -0
  57. data/plugin/dtrace/lib/dtrace_report.rb +67 -0
  58. data/plugin/dtrace/lib/dtracer.rb +52 -0
  59. data/plugin/dtrace/lib/dtracer_client.rb +26 -0
  60. data/plugin/dtrace/public/stylesheets/dtrace.css +48 -0
  61. data/plugin/dtrace/scripts/default.d +11 -0
  62. data/plugin/dtrace/scripts/rails_mysql.d +29 -0
  63. data/plugin/dtrace/tasks/dtrace.rake +52 -0
  64. data/plugin/dtrace/test/dtrace_test.rb +8 -0
  65. data/plugin/dtrace/views/dtrace/_report.rhtml +26 -0
  66. data/test/apple-dof +0 -0
  67. data/test/disabled_probe_effect.txt +19 -0
  68. data/test/dof +0 -0
  69. data/test/dof2 +0 -0
  70. data/test/test_disabled_probe_effect.rb +60 -0
  71. data/test/test_dof_generator.rb +142 -0
  72. data/test/test_dof_helper.rb +106 -0
  73. data/test/test_dof_parser.rb +25 -0
  74. data/test/test_dof_providers.rb +282 -0
  75. data/test/test_dof_strtabs.rb +92 -0
  76. data/test/test_dtrace.rb +111 -0
  77. data/test/test_dtrace_aggregates.rb +56 -0
  78. data/test/test_dtrace_drops_errors.rb +183 -0
  79. data/test/test_dtrace_probe.rb +383 -0
  80. data/test/test_dtrace_probes.rb +400 -0
  81. data/test/test_dtrace_processes.rb +83 -0
  82. data/test/test_dtrace_profile.rb +232 -0
  83. data/test/test_dtrace_provider.rb +153 -0
  84. data/test/test_dtrace_repeat.rb +51 -0
  85. data/test/test_dtrace_rubyprobe.rb +52 -0
  86. data/test/test_dtrace_typefilter.rb +108 -0
  87. data/test/test_legacy_consumer.rb +56 -0
  88. metadata +165 -0
data/History.txt ADDED
@@ -0,0 +1,34 @@
1
+ == 0.0.6 / 2008-02-17
2
+
3
+ * Add Dtrace::Provider, which allows creation of USDT providers from
4
+ Ruby, without the need to patch the interpreter.
5
+
6
+ == 0.0.5 / 2008-01-24
7
+
8
+ * Add DtraceErrData and DtraceDropData for access to error
9
+ and drop information
10
+ * Fix interaction with Ruby's GC
11
+
12
+ == 0.0.4 / 2008-01-14
13
+
14
+ * Fix the very basic Rails plugin.
15
+
16
+ == 0.0.3 / 2008-01-06
17
+
18
+ * Add a DtraceData class which consumers return, containing
19
+ the data returned from each probe firing, rather than
20
+ returning the raw records directly from DTrace.
21
+ * Provide access to probe, CPU and flow information.
22
+ * Allow creation and grabbing of processes.
23
+ * Add an example script: a port of scsi.d.
24
+
25
+ == 0.0.2 / 2007-12-07
26
+
27
+ * Implement the dtrace_work-based API
28
+ * Add a "Consumer" class
29
+ * Update Rails plugin to use new API
30
+
31
+ == 0.0.1 / 2007-12-01
32
+
33
+ * Initial public release.
34
+
data/Manifest.txt ADDED
@@ -0,0 +1,58 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ examples/scsi.rb
6
+ ext/dtrace_aggdata.c
7
+ ext/dtrace_api.c
8
+ ext/dtrace_api.h
9
+ ext/dtrace_bufdata.c
10
+ ext/dtrace_dropdata.c
11
+ ext/dtrace_errdata.c
12
+ ext/dtrace_hdl.c
13
+ ext/dtrace_probe.c
14
+ ext/dtrace_probedata.c
15
+ ext/dtrace_process.c
16
+ ext/dtrace_program.c
17
+ ext/dtrace_programinfo.c
18
+ ext/dtrace_recdesc.c
19
+ ext/dtrace_util.c
20
+ ext/extconf.rb
21
+ lib/dtrace.rb
22
+ lib/dtrace/probe.rb
23
+ lib/dtrace/provider.rb
24
+ lib/dtrace/provider/osx.rb
25
+ lib/dtrace/provider/solaris.rb
26
+ lib/dtrace/tracer.rb
27
+ lib/dtraceaggregate.rb
28
+ lib/dtraceaggregateset.rb
29
+ lib/dtraceconsumer.rb
30
+ lib/dtracedata.rb
31
+ lib/dtraceprintfrecord.rb
32
+ lib/dtraceprobe.rb
33
+ lib/dtraceprobedata.rb
34
+ lib/dtracerecord.rb
35
+ lib/dtracestackrecord.rb
36
+ plugin/dtrace/README
37
+ plugin/dtrace/Rakefile
38
+ plugin/dtrace/bin/dtracer.rb
39
+ plugin/dtrace/init.rb
40
+ plugin/dtrace/lib/dtrace_helper.rb
41
+ plugin/dtrace/lib/dtrace_report.rb
42
+ plugin/dtrace/lib/dtracer.rb
43
+ plugin/dtrace/lib/dtracer_client.rb
44
+ plugin/dtrace/public/stylesheets/dtrace.css
45
+ plugin/dtrace/scripts/default.d
46
+ plugin/dtrace/scripts/rails_mysql.d
47
+ plugin/dtrace/tasks/dtrace.rake
48
+ plugin/dtrace/test/dtrace_test.rb
49
+ plugin/dtrace/views/dtrace/_report.rhtml
50
+ test/test_dtrace.rb
51
+ test/test_dtrace_aggregates.rb
52
+ test/test_dtrace_drops_errors.rb
53
+ test/test_dtrace_processes.rb
54
+ test/test_dtrace_profile.rb
55
+ test/test_dtrace_repeat.rb
56
+ test/test_dtrace_rubyprobe.rb
57
+ test/test_dtrace_typefilter.rb
58
+ test/test_dynusdt.rb
data/README.txt ADDED
@@ -0,0 +1,88 @@
1
+ ruby-dtrace is Ruby bindings for Dtrace, which lets you write D-based
2
+ programs in Ruby, and add probes to your Ruby programs.
3
+
4
+ == FEATURES
5
+
6
+ Consumer:
7
+
8
+ * Access to the D API
9
+ * Probe metadata
10
+ * Run D programs
11
+ * Access aggregates
12
+ * Consume output from D programs
13
+
14
+ Probes:
15
+
16
+ * Create USDT providers from Ruby
17
+ * No code-generation or gcc/linker dependency
18
+
19
+ == SYNOPSIS
20
+
21
+ Consumer:
22
+
23
+ t = Dtrace.new
24
+ progtext = 'ruby$1:::function-entry{ @a[strjoin(strjoin(copyinstr(arg0),"."),copyinstr(arg1))] = count(); } END { printa(@a); }'
25
+ prog = t.compile progtext
26
+ prog.execute
27
+
28
+ t.go
29
+
30
+ [...]
31
+
32
+ c = DtraceConsumer.new(t)
33
+ c.consume_once do |rec|
34
+ # handle records
35
+ end
36
+
37
+ Probes:
38
+
39
+ Dtrace::Provider.create :rubyprog do |p|
40
+ p.probe :foo, :string, :string
41
+ p.probe :bar, :integer, :integer
42
+ end
43
+
44
+ Dtrace::Probe::Rubyprog.foo do |p|
45
+ p.fire('fired!', 'again')
46
+ end
47
+
48
+ Dtrace::Probe::Rubyprog.bar do |p|
49
+ p.fire(42, 27)
50
+ end
51
+
52
+ == REQUIREMENTS
53
+
54
+ * For the consumer API, platform with DTrace support (OpenSolaris, Mac
55
+ OS X 10.5 Leopard tested, possibly also FreeBSD).
56
+
57
+ * For the probe API, a platform with DTrace support, on i386. (Mac OS
58
+ X on PowerPC, Solaris on SPARC and FreeBSD on anything to come).
59
+
60
+ * root, or some/all of the dtrace privileges on Solaris: dtrace_user,
61
+ dtrace_proc and dtrace_kernel.
62
+
63
+ == INSTALL
64
+
65
+ $ sudo gem install ruby-dtrace
66
+
67
+ == LICENSE
68
+
69
+ Copyright (c) 2007 Chris Andrews <chris@nodnol.org>
70
+
71
+ Permission is hereby granted, free of charge, to any person obtaining
72
+ a copy of this software and associated documentation files (the
73
+ 'Software'), to deal in the Software without restriction, including
74
+ without limitation the rights to use, copy, modify, merge, publish,
75
+ distribute, sublicense, and/or sell copies of the Software, and to
76
+ permit persons to whom the Software is furnished to do so, subject to
77
+ the following conditions:
78
+
79
+ The above copyright notice and this permission notice shall be
80
+ included in all copies or substantial portions of the Software.
81
+
82
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
83
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
84
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
85
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
86
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
87
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
88
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,73 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/packagetask'
7
+ require 'rake/gempackagetask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+
10
+ $: << './lib'
11
+ require 'dtrace/version'
12
+
13
+ desc "Uses extconf.rb and make to build the extension"
14
+ task :extensions do
15
+ Dir.chdir('ext')
16
+ system("ruby extconf.rb")
17
+ system("make")
18
+ Dir.chdir('dof')
19
+ system("ruby extconf.rb")
20
+ system("make")
21
+ Dir.chdir('../..')
22
+ end
23
+
24
+ desc "Clean all extensions"
25
+ task :clean_extensions do
26
+ Dir.chdir('ext')
27
+ system("make clean")
28
+ Dir.chdir('dof')
29
+ system("make clean")
30
+ Dir.chdir('../..')
31
+ end
32
+
33
+ PKG_NAME = "ruby-dtrace"
34
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
35
+ PKG_VERSION = Dtrace::VERSION + PKG_BUILD
36
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
37
+
38
+ desc "Default task"
39
+ task :default => [ :test ]
40
+
41
+ desc "Build documentation"
42
+ task :doc => [ :rdoc ]
43
+
44
+ Rake::TestTask.new do |t|
45
+ t.libs << "ext:lib"
46
+ t.test_files = Dir["test/*.rb"]
47
+ t.verbose = true
48
+ end
49
+
50
+ desc "Run code-coverage analysis using rcov"
51
+ task :coverage do
52
+ rm_rf "coverage"
53
+ files = Dir["test/*.rb"]
54
+ system "rcov --sort coverage -Iext:lib #{files.join(' ')}"
55
+ end
56
+
57
+ GEM_SPEC = eval(File.read("#{File.dirname(__FILE__)}/#{PKG_NAME}.gemspec"))
58
+
59
+ Rake::GemPackageTask.new(GEM_SPEC) do |p|
60
+ p.gem_spec = GEM_SPEC
61
+ p.need_tar = true
62
+ p.need_zip = true
63
+ end
64
+
65
+ desc "Build the RDoc API documentation"
66
+ Rake::RDocTask.new do |rdoc|
67
+ rdoc.rdoc_dir = "doc"
68
+ rdoc.title = "Ruby-DTrace"
69
+ rdoc.options += %w(--line-numbers --inline-source --main README.txt)
70
+ rdoc.rdoc_files.include 'README.txt'
71
+ rdoc.rdoc_files.include 'ext/**/*.c'
72
+ rdoc.rdoc_files.include 'lib/**/*.rb'
73
+ end
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
+