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.
- data/History.txt +34 -0
- data/Manifest.txt +58 -0
- data/README.txt +88 -0
- data/Rakefile +73 -0
- data/examples/scsi.rb +442 -0
- data/ext/dof/constants.c +49 -0
- data/ext/dof/dof.h +55 -0
- data/ext/dof/dof_api.c +57 -0
- data/ext/dof/dof_helper.c +82 -0
- data/ext/dof/extconf.rb +4 -0
- data/ext/dof/file.c +56 -0
- data/ext/dof/generator.c +9 -0
- data/ext/dof/header.c +80 -0
- data/ext/dof/parser.c +415 -0
- data/ext/dof/parser.h +10 -0
- data/ext/dof/section.c +302 -0
- data/ext/dtrace_aggdata.c +142 -0
- data/ext/dtrace_api.c +119 -0
- data/ext/dtrace_api.h +150 -0
- data/ext/dtrace_bufdata.c +139 -0
- data/ext/dtrace_dropdata.c +131 -0
- data/ext/dtrace_errdata.c +110 -0
- data/ext/dtrace_hdl.c +577 -0
- data/ext/dtrace_probedata.c +267 -0
- data/ext/dtrace_probedesc.c +78 -0
- data/ext/dtrace_process.c +37 -0
- data/ext/dtrace_program.c +62 -0
- data/ext/dtrace_programinfo.c +60 -0
- data/ext/dtrace_recdesc.c +46 -0
- data/ext/dtrace_util.c +92 -0
- data/ext/extconf.rb +28 -0
- data/ext/stubs.txt +78 -0
- data/lib/dtrace/aggregate.rb +40 -0
- data/lib/dtrace/aggregateset.rb +19 -0
- data/lib/dtrace/consumer.rb +174 -0
- data/lib/dtrace/data.rb +82 -0
- data/lib/dtrace/dof/file.rb +63 -0
- data/lib/dtrace/dof/section/strtab.rb +21 -0
- data/lib/dtrace/dof/section.rb +69 -0
- data/lib/dtrace/dof.rb +8 -0
- data/lib/dtrace/printfrecord.rb +10 -0
- data/lib/dtrace/probe.rb +46 -0
- data/lib/dtrace/probedata.rb +23 -0
- data/lib/dtrace/probedesc.rb +15 -0
- data/lib/dtrace/provider/probedef.rb +24 -0
- data/lib/dtrace/provider.rb +231 -0
- data/lib/dtrace/record.rb +11 -0
- data/lib/dtrace/stackrecord.rb +31 -0
- data/lib/dtrace/tracer.rb +35 -0
- data/lib/dtrace.rb +74 -0
- data/lib/dtraceconsumer.rb +9 -0
- data/plugin/dtrace/README +81 -0
- data/plugin/dtrace/Rakefile +22 -0
- data/plugin/dtrace/bin/dtracer.rb +29 -0
- data/plugin/dtrace/init.rb +7 -0
- data/plugin/dtrace/lib/dtrace_helper.rb +2 -0
- data/plugin/dtrace/lib/dtrace_report.rb +67 -0
- data/plugin/dtrace/lib/dtracer.rb +52 -0
- data/plugin/dtrace/lib/dtracer_client.rb +26 -0
- data/plugin/dtrace/public/stylesheets/dtrace.css +48 -0
- data/plugin/dtrace/scripts/default.d +11 -0
- data/plugin/dtrace/scripts/rails_mysql.d +29 -0
- data/plugin/dtrace/tasks/dtrace.rake +52 -0
- data/plugin/dtrace/test/dtrace_test.rb +8 -0
- data/plugin/dtrace/views/dtrace/_report.rhtml +26 -0
- data/test/apple-dof +0 -0
- data/test/disabled_probe_effect.txt +19 -0
- data/test/dof +0 -0
- data/test/dof2 +0 -0
- data/test/test_disabled_probe_effect.rb +60 -0
- data/test/test_dof_generator.rb +142 -0
- data/test/test_dof_helper.rb +106 -0
- data/test/test_dof_parser.rb +25 -0
- data/test/test_dof_providers.rb +282 -0
- data/test/test_dof_strtabs.rb +92 -0
- data/test/test_dtrace.rb +111 -0
- data/test/test_dtrace_aggregates.rb +56 -0
- data/test/test_dtrace_drops_errors.rb +183 -0
- data/test/test_dtrace_probe.rb +383 -0
- data/test/test_dtrace_probes.rb +400 -0
- data/test/test_dtrace_processes.rb +83 -0
- data/test/test_dtrace_profile.rb +232 -0
- data/test/test_dtrace_provider.rb +153 -0
- data/test/test_dtrace_repeat.rb +51 -0
- data/test/test_dtrace_rubyprobe.rb +52 -0
- data/test/test_dtrace_typefilter.rb +108 -0
- data/test/test_legacy_consumer.rb +56 -0
- 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
|
+
|