ruby-dtrace 0.0.6 → 0.2.8
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 +21 -0
- data/Manifest.txt +86 -19
- data/README.txt +48 -6
- data/Rakefile +61 -20
- data/examples/scsi.rb +1 -1
- data/ext/dof/Makefile +154 -0
- data/ext/dof/constants.c +57 -0
- data/ext/dof/dof.h +56 -0
- data/ext/dof/dof_api.c +58 -0
- data/ext/dof/dof_helper.c +82 -0
- data/ext/dof/extconf.rb +4 -0
- data/ext/dof/file.c +90 -0
- data/ext/dof/generator.c +9 -0
- data/ext/dof/header.c +79 -0
- data/ext/dof/mkmf.log +10 -0
- data/ext/dof/parser.c +415 -0
- data/ext/dof/parser.h +10 -0
- data/ext/dof/section.c +312 -0
- data/ext/dtrace_aggdata.c +2 -2
- data/ext/dtrace_api.c +46 -34
- data/ext/dtrace_api.h +31 -7
- data/ext/dtrace_bufdata.c +3 -3
- data/ext/dtrace_hdl.c +66 -3
- data/ext/dtrace_probedata.c +4 -4
- data/ext/{dtrace_probe.c → dtrace_probedesc.c} +7 -7
- data/ext/extconf.rb +25 -0
- data/ext/i386-darwin/dtrace_probe.c +278 -0
- data/ext/i386-solaris/dtrace_probe.c +225 -0
- data/ext/stubs.txt +78 -0
- data/lib/dtrace.rb +34 -13
- 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.rb +8 -0
- data/lib/dtrace/dof/file.rb +64 -0
- data/lib/dtrace/dof/section.rb +75 -0
- data/lib/dtrace/dof/section/strtab.rb +28 -0
- data/lib/{dtraceprintfrecord.rb → dtrace/printfrecord.rb} +4 -2
- data/lib/dtrace/probe.rb +3 -6
- data/lib/dtrace/probedata.rb +23 -0
- data/lib/dtrace/probedesc.rb +15 -0
- data/lib/dtrace/provider.rb +190 -169
- data/lib/dtrace/provider/klass.rb +33 -0
- data/lib/dtrace/provider/probedef.rb +24 -0
- data/lib/{dtracerecord.rb → dtrace/record.rb} +4 -2
- data/lib/{dtracestackrecord.rb → dtrace/stackrecord.rb} +10 -8
- data/lib/dtrace/version.rb +9 -0
- data/lib/dtraceconsumer.rb +3 -167
- data/plugin/dtrace/lib/dtracer.rb +4 -4
- 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 +56 -0
- data/test/test_dof_generator.rb +142 -0
- data/test/test_dof_helper.rb +106 -0
- data/test/test_dof_parser.rb +27 -0
- data/test/test_dof_providers.rb +278 -0
- data/test/test_dof_strtabs.rb +98 -0
- data/test/test_dtrace.rb +67 -1
- data/test/test_dtrace_aggregates.rb +5 -5
- data/test/test_dtrace_drops_errors.rb +5 -5
- data/test/test_dtrace_probe.rb +385 -0
- data/test/test_dtrace_probes.rb +414 -0
- data/test/test_dtrace_processes.rb +2 -2
- data/test/test_dtrace_profile.rb +12 -12
- data/test/test_dtrace_provider.rb +138 -0
- data/test/test_dtrace_repeat.rb +1 -1
- data/test/test_dtrace_rubyprobe.rb +3 -1
- data/test/test_dtrace_typefilter.rb +9 -9
- data/test/test_legacy_consumer.rb +56 -0
- metadata +112 -71
- data/lib/dtrace/provider/osx.rb +0 -25
- data/lib/dtrace/provider/solaris.rb +0 -29
- data/lib/dtraceaggregate.rb +0 -37
- data/lib/dtraceaggregateset.rb +0 -17
- data/lib/dtracedata.rb +0 -80
- data/lib/dtraceprobe.rb +0 -13
- data/lib/dtraceprobedata.rb +0 -21
- data/test/test_dynusdt.rb +0 -135
data/lib/dtrace/dof.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace::Dof::File
|
7
|
+
include Dtrace::Dof::Constants
|
8
|
+
attr_accessor :sections
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@sections = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate
|
15
|
+
hdr = Dtrace::Dof::Header.new
|
16
|
+
hdr.secnum = @sections.length
|
17
|
+
filesz = hdr.hdrlen
|
18
|
+
loadsz = filesz
|
19
|
+
dof_version = 1
|
20
|
+
|
21
|
+
@sections.each do |s|
|
22
|
+
# Presence of is_enabled probes forces DOF version 2.
|
23
|
+
if s.section_type == DOF_SECT_PRENOFFS
|
24
|
+
dof_version = 2
|
25
|
+
end
|
26
|
+
|
27
|
+
length = s.generate
|
28
|
+
s.offset = filesz
|
29
|
+
|
30
|
+
pad = 0
|
31
|
+
if s.align > 1
|
32
|
+
i = s.offset.to_f % s.align
|
33
|
+
if i > 0
|
34
|
+
pad = (s.align - i).to_i
|
35
|
+
s.offset = pad + s.offset
|
36
|
+
s.pad = "\000" * pad
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
s.size = length
|
41
|
+
|
42
|
+
loadsz += (s.size + pad) if (s.flags & 1) == 1 # DOF_SECF_LOAD
|
43
|
+
filesz += (s.size + pad)
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
hdr.loadsz = loadsz
|
48
|
+
hdr.filesz = filesz
|
49
|
+
hdr.dof_version = dof_version
|
50
|
+
|
51
|
+
self << hdr.generate
|
52
|
+
|
53
|
+
@sections.each do |s|
|
54
|
+
self << s.generate_header
|
55
|
+
end
|
56
|
+
|
57
|
+
@sections.each do |s|
|
58
|
+
self << s.pad if s.pad
|
59
|
+
self << s.dof
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'dtrace/dof/section/strtab'
|
7
|
+
|
8
|
+
class Dtrace::Dof::Section
|
9
|
+
include Dtrace::Dof::Constants
|
10
|
+
attr_writer :entsize
|
11
|
+
attr_accessor :flags, :data, :offset, :align, :pad, :size
|
12
|
+
attr_reader :section_type, :dof
|
13
|
+
|
14
|
+
def initialize(type, index)
|
15
|
+
@section_type = type
|
16
|
+
@index = index
|
17
|
+
@flags = 1 # DOF_SECF_LOAD
|
18
|
+
@data = {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate
|
22
|
+
case @section_type
|
23
|
+
when DOF_SECT_COMMENTS
|
24
|
+
@align = 1
|
25
|
+
@dof = dof_generate_comments
|
26
|
+
when DOF_SECT_STRTAB
|
27
|
+
@align = 1
|
28
|
+
@dof = dof_generate_strtab
|
29
|
+
when DOF_SECT_PROBES
|
30
|
+
@align = 8
|
31
|
+
@dof = dof_generate_probes
|
32
|
+
when DOF_SECT_PRARGS
|
33
|
+
@align = 1
|
34
|
+
@dof = dof_generate_prargs
|
35
|
+
when DOF_SECT_PROFFS
|
36
|
+
@align = 4
|
37
|
+
@dof = dof_generate_proffs
|
38
|
+
when DOF_SECT_PRENOFFS
|
39
|
+
@align = 4
|
40
|
+
@dof = dof_generate_prenoffs
|
41
|
+
when DOF_SECT_PROVIDER
|
42
|
+
@align = 4
|
43
|
+
@dof = dof_generate_provider
|
44
|
+
when DOF_SECT_RELTAB
|
45
|
+
@align = 8
|
46
|
+
@dof = dof_generate_reltab
|
47
|
+
when DOF_SECT_URELHDR
|
48
|
+
@align = 4
|
49
|
+
@dof = dof_generate_relhdr
|
50
|
+
when DOF_SECT_UTSNAME
|
51
|
+
@align = 1
|
52
|
+
@dof = dof_generate_utsname
|
53
|
+
else
|
54
|
+
@dof = ''
|
55
|
+
end
|
56
|
+
|
57
|
+
@entsize = compute_entsize
|
58
|
+
|
59
|
+
return @dof.length
|
60
|
+
end
|
61
|
+
|
62
|
+
def compute_entsize
|
63
|
+
begin
|
64
|
+
if @data.class == Array
|
65
|
+
entsize = @dof.length / @data.length
|
66
|
+
else
|
67
|
+
entsize = 0
|
68
|
+
end
|
69
|
+
rescue ZeroDivisionError
|
70
|
+
entsize = 0
|
71
|
+
end
|
72
|
+
entsize
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace::Dof::Section::Strtab < Dtrace::Dof::Section
|
7
|
+
def initialize(index)
|
8
|
+
super(DOF_SECT_STRTAB, index)
|
9
|
+
self.data = []
|
10
|
+
@idx = 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def add(string)
|
14
|
+
idx = @idx
|
15
|
+
string = string.to_s
|
16
|
+
@idx += (string.length + 1)
|
17
|
+
self.data << string
|
18
|
+
return idx
|
19
|
+
end
|
20
|
+
|
21
|
+
def length
|
22
|
+
return @idx
|
23
|
+
end
|
24
|
+
|
25
|
+
def compute_entsize
|
26
|
+
0
|
27
|
+
end
|
28
|
+
end
|
data/lib/dtrace/probe.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
#
|
2
2
|
# Ruby-Dtrace
|
3
|
-
# (c)
|
4
|
-
#
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
5
4
|
|
6
5
|
class Dtrace
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
6
|
+
# Using dynamically created USDT probes in Ruby programs.
|
7
|
+
#
|
10
8
|
# Having created the following probes with Dtrace::Provider:
|
11
9
|
#
|
12
10
|
# 74777 action_controller12297 action_controller.so process_finish process-finish
|
@@ -46,4 +44,3 @@ class Dtrace
|
|
46
44
|
class Probe
|
47
45
|
end
|
48
46
|
end
|
49
|
-
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Ruby-Dtrace
|
3
|
+
# (c) 2007 Chris Andrews <chris@nodnol.org>
|
4
|
+
#
|
5
|
+
|
6
|
+
class Dtrace
|
7
|
+
class ProbeData
|
8
|
+
|
9
|
+
def records
|
10
|
+
records = Array.new
|
11
|
+
self.each_record do |rec|
|
12
|
+
records << rec
|
13
|
+
end
|
14
|
+
records
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
rs = self.records
|
19
|
+
rs.map {|r| r.value }.join ', '
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/dtrace/provider.rb
CHANGED
@@ -1,61 +1,28 @@
|
|
1
1
|
#
|
2
2
|
# Ruby-Dtrace
|
3
|
-
# (c)
|
3
|
+
# (c) 2008 Chris Andrews <chris@nodnol.org>
|
4
4
|
#
|
5
5
|
|
6
|
+
require 'dtrace'
|
7
|
+
require 'dtrace/dof'
|
6
8
|
require 'dtrace/probe'
|
7
|
-
require 'dtrace/provider/
|
8
|
-
require 'dtrace/provider/
|
9
|
-
require 'pathname'
|
10
|
-
require 'tempfile'
|
11
|
-
|
12
|
-
DTRACE = '/usr/sbin/dtrace'
|
9
|
+
require 'dtrace/provider/probedef'
|
10
|
+
require 'dtrace/provider/klass'
|
13
11
|
|
14
12
|
class Dtrace
|
15
13
|
|
16
14
|
# A DTrace provider. Allows creation of USDT probes on a running
|
17
|
-
# Ruby program
|
18
|
-
#
|
19
|
-
# this with a Ruby interpreter compiled with the core DTrace probes,
|
20
|
-
# but you don't have to.
|
21
|
-
#
|
22
|
-
# This requires the DTrace and Ruby toolchains to be available:
|
23
|
-
# dtrace(1M), and the compiler and linker used to build Ruby. The
|
24
|
-
# process is similar to RubyInline, but the actual RubyInline
|
25
|
-
# library is not required (the build process for DTrace USDT probes
|
26
|
-
# is sufficiently differnent to a standard Ruby extension that it's
|
27
|
-
# not worth using it).
|
28
|
-
#
|
29
|
-
# Both Solaris and OSX 10.5 are supported. Other DTrace-supporting
|
30
|
-
# platforms can be added by creating a new class under
|
31
|
-
# Dtrace::Provider and implementing or overriding the required steps
|
32
|
-
# in the build process.
|
15
|
+
# Ruby program. You can use this with a Ruby interpreter compiled
|
16
|
+
# with the core DTrace probes, but you don't have to.
|
33
17
|
#
|
34
18
|
# Firing probes is explained in Dtrace::Probe.
|
35
19
|
#
|
36
|
-
# There are some limitations:
|
37
|
-
#
|
38
|
-
# You cannot choose all the components of the probe name: you can
|
39
|
-
# choose the provider and probe name, but the module and function
|
40
|
-
# components will be derived by DTrace, and won't be meaningful
|
41
|
-
# (they'll refer to the shim extension that gets created, not to
|
42
|
-
# anything in your Ruby program). It seems unlikely it's possible to
|
43
|
-
# change this.
|
44
|
-
#
|
45
|
-
# You cannot currently set D attributes: they're hardcoded to a
|
46
|
-
# default set. This will change.
|
47
|
-
#
|
48
|
-
# The extension will currently be rebuilt every time the provider is
|
49
|
-
# created, as there's not yet any support for packaging the provider
|
50
|
-
# in some way. This will change, to something along the lines of
|
51
|
-
# what RubyInline does to allow a pre-built extension to be used.
|
52
|
-
#
|
53
20
|
class Provider
|
21
|
+
include Dtrace::Dof::Constants
|
54
22
|
|
55
|
-
|
23
|
+
Typemap = { :string => 'char *', :integer => 'int' }
|
56
24
|
|
57
|
-
# Creates a DTrace provider.
|
58
|
-
# and loaded, implementing the probes.
|
25
|
+
# Creates a DTrace provider.
|
59
26
|
#
|
60
27
|
# Example:
|
61
28
|
#
|
@@ -71,12 +38,15 @@ class Dtrace
|
|
71
38
|
# create yields a Provider for the current platform, on which you
|
72
39
|
# can call probe, to create the individual probes.
|
73
40
|
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
41
|
+
# You can override the module name in the created probes, by
|
42
|
+
# passing in an hash:
|
43
|
+
#
|
44
|
+
# Dtrace::Provider.create :foo, { :module => 'somemodule' } do |p|
|
45
|
+
# p.probe...
|
46
|
+
# end
|
47
|
+
def self.create(name, options={})
|
48
|
+
options[:module] ||= 'ruby'
|
49
|
+
provider = Dtrace::Provider.new(name, options[:module])
|
80
50
|
yield provider
|
81
51
|
provider.enable
|
82
52
|
end
|
@@ -88,61 +58,192 @@ class Dtrace
|
|
88
58
|
# :string (char *)
|
89
59
|
# :integer (int)
|
90
60
|
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
# provider_name:provider_name.so:probe_name:probe-name
|
61
|
+
# Providing an options hash as the second argument allows you to
|
62
|
+
# override the function name, otherwise it will be taken from the
|
63
|
+
# caller of this function:
|
95
64
|
#
|
96
|
-
#
|
97
|
-
# this redundancy in probe names.
|
65
|
+
# p.probe :foo, { :function => 'somefunction' }, :int, ...
|
98
66
|
#
|
99
67
|
def probe(name, *types)
|
100
|
-
|
101
|
-
|
68
|
+
options = {}
|
69
|
+
if types[0].respond_to? :keys
|
70
|
+
options = types.shift
|
71
|
+
end
|
72
|
+
caller = Kernel.caller[0].match(/`(.*)'/)
|
73
|
+
if caller
|
74
|
+
options[:function] ||= caller[1]
|
75
|
+
else
|
76
|
+
options[:function] ||= name
|
77
|
+
end
|
78
|
+
|
79
|
+
pd = Dtrace::Provider::ProbeDef.new(name, options[:function])
|
80
|
+
types.each do |t|
|
81
|
+
if Typemap[t].nil?
|
82
|
+
raise Dtrace::Exception.new("type '#{t}' invalid")
|
83
|
+
else
|
84
|
+
pd.args << Typemap[t]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
@probe_defs << pd
|
102
89
|
end
|
103
90
|
|
104
|
-
def initialize(
|
105
|
-
@name
|
106
|
-
@
|
107
|
-
@
|
91
|
+
def initialize(provider_name, module_name)
|
92
|
+
@name = provider_name.to_s
|
93
|
+
@module = module_name.to_s
|
94
|
+
@class = camelize(provider_name)
|
95
|
+
@probe_defs = []
|
96
|
+
end
|
97
|
+
|
98
|
+
# attempt to turn the probe_count into the eventual size of DOF
|
99
|
+
# we'll need, based on the current state of the strtab.
|
100
|
+
def dof_size
|
101
|
+
probes = @probe_defs.length
|
102
|
+
args = (@probe_defs.inject(0) {|sum, pd| sum + pd.args.length }) + 1
|
103
|
+
|
104
|
+
size = 0
|
105
|
+
[
|
106
|
+
DOF_DOFHDR_SIZE,
|
107
|
+
DOF_SECHDR_SIZE * 6, # we have 6 sections, see provider.rb
|
108
|
+
@strtab.length, # we're told the size of the string table
|
109
|
+
(DOF_PROBE_SIZE * probes), # probes
|
110
|
+
(DOF_PRARGS_SIZE * args), # prargs
|
111
|
+
(DOF_PROFFS_SIZE * probes), # proffs
|
112
|
+
(DOF_PRENOFFS_SIZE * probes), # prenoffs
|
113
|
+
DOF_PROVIDER_SIZE # provider
|
114
|
+
].each do |sec|
|
115
|
+
size += sec
|
116
|
+
i = size.to_f % 8 # assume longest alignment, 8, will overestimate but not by much
|
117
|
+
if i > 0
|
118
|
+
size += (8 - i).to_i
|
119
|
+
end
|
120
|
+
end
|
121
|
+
size
|
108
122
|
end
|
109
123
|
|
110
124
|
def enable
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
125
|
+
@strtab = Dtrace::Dof::Section::Strtab.new(0)
|
126
|
+
provider_name_idx = @strtab.add(@name)
|
127
|
+
|
128
|
+
f = Dtrace::Dof::File.new
|
129
|
+
f.sections << @strtab
|
130
|
+
|
131
|
+
s = Dtrace::Dof::Section.new(DOF_SECT_PROBES, 1)
|
132
|
+
probes = Array.new
|
133
|
+
stubs = Hash.new
|
134
|
+
argidx = 0
|
135
|
+
offidx = 0
|
136
|
+
@probe_defs.each do |pd|
|
137
|
+
argc = pd.argc
|
138
|
+
|
139
|
+
argv = 0
|
140
|
+
pd.args.each do |type|
|
141
|
+
i = @strtab.add(type)
|
142
|
+
argv = i if argv == 0
|
118
143
|
end
|
144
|
+
|
145
|
+
probe = Dtrace::Probe.new(argc)
|
146
|
+
probes <<
|
147
|
+
{
|
148
|
+
:name => @strtab.add(pd.name),
|
149
|
+
:func => @strtab.add(pd.function),
|
150
|
+
:noffs => 1,
|
151
|
+
:enoffidx => offidx,
|
152
|
+
:argidx => argidx,
|
153
|
+
:nenoffs => 1,
|
154
|
+
:offidx => offidx,
|
155
|
+
:addr => probe.addr,
|
156
|
+
:nargc => argc,
|
157
|
+
:xargc => argc,
|
158
|
+
:nargv => argv,
|
159
|
+
:xargv => argv,
|
160
|
+
}
|
161
|
+
|
162
|
+
stubs[pd.name] = probe
|
163
|
+
argidx += argc
|
164
|
+
offidx += 1
|
165
|
+
end
|
166
|
+
s.data = probes
|
167
|
+
f.sections << s
|
119
168
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
link
|
127
|
-
load
|
169
|
+
s = Dtrace::Dof::Section.new(DOF_SECT_PRARGS, 2)
|
170
|
+
s.data = Array.new
|
171
|
+
@probe_defs.each do |pd|
|
172
|
+
pd.args.each_with_index do |arg, i|
|
173
|
+
s.data << i
|
174
|
+
end
|
128
175
|
end
|
129
|
-
|
176
|
+
if s.data.empty?
|
177
|
+
s.data = [ 0 ]
|
178
|
+
end
|
179
|
+
f.sections << s
|
180
|
+
|
181
|
+
# After last addition to strtab, but before first offset!
|
182
|
+
f.allocate(self.dof_size)
|
130
183
|
|
131
|
-
|
184
|
+
s = Dtrace::Dof::Section.new(DOF_SECT_PROFFS, 3)
|
185
|
+
s.data = Array.new
|
186
|
+
@probe_defs.each do |pd|
|
187
|
+
s.data << stubs[pd.name].probe_offset(f.addr, pd.argc)
|
188
|
+
end
|
189
|
+
if s.data.empty?
|
190
|
+
s.data = [ 0 ]
|
191
|
+
end
|
192
|
+
f.sections << s
|
132
193
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
194
|
+
s = Dtrace::Dof::Section.new(DOF_SECT_PRENOFFS, 4)
|
195
|
+
s.data = Array.new
|
196
|
+
@probe_defs.each do |pd|
|
197
|
+
s.data << stubs[pd.name].is_enabled_offset(f.addr)
|
137
198
|
end
|
138
|
-
|
199
|
+
if s.data.empty?
|
200
|
+
s.data = [ 0 ]
|
201
|
+
end
|
202
|
+
f.sections << s
|
203
|
+
|
204
|
+
s = Dtrace::Dof::Section.new(DOF_SECT_PROVIDER, 5)
|
205
|
+
s.data = {
|
206
|
+
:strtab => 0,
|
207
|
+
:probes => 1,
|
208
|
+
:prargs => 2,
|
209
|
+
:proffs => 3,
|
210
|
+
:prenoffs => 4,
|
211
|
+
:name => provider_name_idx,
|
212
|
+
:provattr => {
|
213
|
+
:name => DTRACE_STABILITY_EVOLVING,
|
214
|
+
:data => DTRACE_STABILITY_EVOLVING,
|
215
|
+
:class => DTRACE_STABILITY_EVOLVING
|
216
|
+
},
|
217
|
+
:modattr => {
|
218
|
+
:name => DTRACE_STABILITY_PRIVATE,
|
219
|
+
:data => DTRACE_STABILITY_PRIVATE,
|
220
|
+
:class => DTRACE_STABILITY_EVOLVING
|
221
|
+
},
|
222
|
+
:funcattr => {
|
223
|
+
:name => DTRACE_STABILITY_PRIVATE,
|
224
|
+
:data => DTRACE_STABILITY_PRIVATE,
|
225
|
+
:class => DTRACE_STABILITY_EVOLVING
|
226
|
+
},
|
227
|
+
:nameattr => {
|
228
|
+
:name => DTRACE_STABILITY_EVOLVING,
|
229
|
+
:data => DTRACE_STABILITY_EVOLVING,
|
230
|
+
:class => DTRACE_STABILITY_EVOLVING
|
231
|
+
},
|
232
|
+
:argsattr => {
|
233
|
+
:name => DTRACE_STABILITY_EVOLVING,
|
234
|
+
:data => DTRACE_STABILITY_EVOLVING,
|
235
|
+
:class => DTRACE_STABILITY_EVOLVING
|
236
|
+
},
|
237
|
+
}
|
238
|
+
f.sections << s
|
239
|
+
|
240
|
+
f.generate
|
241
|
+
Dtrace::Dof.loaddof(f, @module)
|
242
|
+
|
243
|
+
provider = Dtrace::Provider::Klass.new(f, stubs)
|
244
|
+
Dtrace::Probe.const_set(@class, provider)
|
139
245
|
|
140
|
-
|
141
|
-
%w(srcdir archdir).map { |name|
|
142
|
-
dir = Config::CONFIG[name]
|
143
|
-
}.find { |dir|
|
144
|
-
dir and File.exist? File.join(dir, "/ruby.h")
|
145
|
-
} or abort "ERROR: Can't find header dir for ruby. Exiting..."
|
246
|
+
provider
|
146
247
|
end
|
147
248
|
|
148
249
|
private
|
@@ -151,86 +252,6 @@ class Dtrace
|
|
151
252
|
# Pinched from ActiveSupport's Inflector
|
152
253
|
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
153
254
|
end
|
154
|
-
|
155
|
-
# compose provider definition .d file
|
156
|
-
def definition
|
157
|
-
stability = <<EOS
|
158
|
-
#pragma D attributes Evolving/Evolving/Common provider #{@name} provider
|
159
|
-
#pragma D attributes Private/Private/Common provider #{@name} module
|
160
|
-
#pragma D attributes Private/Private/Common provider #{@name} function
|
161
|
-
#pragma D attributes Evolving/Evolving/Common provider #{@name} name
|
162
|
-
#pragma D attributes Evolving/Evolving/Common provider #{@name} args
|
163
|
-
EOS
|
164
|
-
File.open("#{@tempdir}/probes.d", 'w') do |io|
|
165
|
-
io << "provider #{@name} {\n"
|
166
|
-
@probes.each_pair do |name, types|
|
167
|
-
probename = name.to_s.gsub(/_/, '__')
|
168
|
-
typesdesc = types.join(', ')
|
169
|
-
probedesc = " probe #{probename}(#{typesdesc});\n"
|
170
|
-
io << probedesc
|
171
|
-
end
|
172
|
-
io << "\n};\n\n#{stability}"
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def header
|
177
|
-
run "#{DTRACE} -h -s #{@tempdir}/probes.d -o #{@tempdir}/probes.h"
|
178
|
-
end
|
179
|
-
|
180
|
-
# Generate the C source for the provider class
|
181
|
-
def source
|
182
|
-
rb2c = { 'char *' => 'STR2CSTR', 'int' => 'FIX2INT' }
|
183
|
-
|
184
|
-
File.open("#{@tempdir}/probes.c", 'w') do |io|
|
185
|
-
io.puts '#include "ruby.h"'
|
186
|
-
io.puts "#include \"#{@tempdir}/probes.h\""
|
187
|
-
|
188
|
-
@probes.each_pair do |name, types|
|
189
|
-
defn_args = []
|
190
|
-
call_args = []
|
191
|
-
types.each_with_index { |type, i| defn_args << "#{type} arg#{i}" }
|
192
|
-
types.each_with_index { |type, i| call_args << "#{rb2c[type]}(rb_ary_entry(args, #{i}))" }
|
193
|
-
|
194
|
-
io.puts <<EOC
|
195
|
-
static VALUE #{name}(VALUE self) {
|
196
|
-
if (#{@name.upcase}_#{name.to_s.upcase}_ENABLED()) {
|
197
|
-
VALUE args = rb_yield(self);
|
198
|
-
#{@name.upcase}_#{name.to_s.upcase}(#{call_args.join(', ')});
|
199
|
-
}
|
200
|
-
return Qnil;
|
201
|
-
}
|
202
|
-
EOC
|
203
|
-
end
|
204
|
-
io.puts <<EOC
|
205
|
-
static VALUE fire(VALUE self, VALUE args) {
|
206
|
-
return args;
|
207
|
-
}
|
208
|
-
|
209
|
-
void Init_#{@name}() {
|
210
|
-
VALUE c = rb_cObject;
|
211
|
-
rb_define_method(c, "fire", (VALUE(*)(ANYARGS))fire, -2);
|
212
|
-
EOC
|
213
|
-
|
214
|
-
@probes.each_pair do |name, types|
|
215
|
-
io.puts " rb_define_singleton_method(c, \"#{name}\", (VALUE(*)(ANYARGS))#{name}, 0);"
|
216
|
-
end
|
217
|
-
|
218
|
-
io.puts '}'
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
def load
|
223
|
-
# Load the generated extension with a full path (saves adjusting
|
224
|
-
# $:) Done in the context of an anonymous class, since the
|
225
|
-
# module does not itself define a class. TODO: find a way of
|
226
|
-
# doing this without string eval...
|
227
|
-
lib = "#{@tempdir}/#{@name}"
|
228
|
-
c = Class.new
|
229
|
-
c.module_eval do
|
230
|
-
require lib
|
231
|
-
end
|
232
|
-
eval "Dtrace::Probe::#{@class} = c"
|
233
|
-
end
|
234
255
|
|
235
256
|
end
|
236
257
|
end
|