ruby-dtrace 0.0.1
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 +3 -0
- data/Manifest.txt +28 -0
- data/README.txt +60 -0
- data/Rakefile +30 -0
- data/ext/dtrace_aggregate.c +150 -0
- data/ext/dtrace_api.c +69 -0
- data/ext/dtrace_api.h +53 -0
- data/ext/dtrace_hdl.c +280 -0
- data/ext/dtrace_probe.c +78 -0
- data/ext/dtrace_program.c +57 -0
- data/ext/dtrace_programinfo.c +60 -0
- data/ext/dtrace_recdesc.c +38 -0
- data/ext/extconf.rb +4 -0
- data/lib/dtrace.rb +11 -0
- data/plugin/dtrace/README +4 -0
- data/plugin/dtrace/Rakefile +22 -0
- data/plugin/dtrace/bin/dtracer.rb +24 -0
- data/plugin/dtrace/init.rb +7 -0
- data/plugin/dtrace/lib/dtrace_helper.rb +2 -0
- data/plugin/dtrace/lib/dtrace_report.rb +47 -0
- data/plugin/dtrace/lib/dtrace_tracer.rb +34 -0
- data/plugin/dtrace/lib/dtracer.rb +43 -0
- data/plugin/dtrace/lib/dtracer_client.rb +18 -0
- data/plugin/dtrace/public/stylesheets/dtrace.css +48 -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 +11 -0
- data/test/test_dtrace.rb +415 -0
- metadata +85 -0
data/ext/dtrace_probe.c
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
/* Ruby-Dtrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
/* :nodoc: */
|
8
|
+
VALUE dtraceprobe_init(VALUE self)
|
9
|
+
{
|
10
|
+
dtrace_probedesc_t *pdp;
|
11
|
+
|
12
|
+
Data_Get_Struct(self, dtrace_probedesc_t, pdp);
|
13
|
+
return self;
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Returns the id of the probe. Corresponds to the ID displayed by
|
18
|
+
* dtrace -l
|
19
|
+
*/
|
20
|
+
VALUE dtraceprobe_probe_id(VALUE self)
|
21
|
+
{
|
22
|
+
dtrace_probedesc_t *pdp;
|
23
|
+
|
24
|
+
Data_Get_Struct(self, dtrace_probedesc_t, pdp);
|
25
|
+
return INT2NUM(pdp->dtpd_id);
|
26
|
+
}
|
27
|
+
|
28
|
+
/*
|
29
|
+
* Returns the name of the probe's provider.
|
30
|
+
*/
|
31
|
+
VALUE dtraceprobe_provider(VALUE self)
|
32
|
+
{
|
33
|
+
VALUE string;
|
34
|
+
dtrace_probedesc_t *pdp;
|
35
|
+
|
36
|
+
Data_Get_Struct(self, dtrace_probedesc_t, pdp);
|
37
|
+
string = rb_str_new2(pdp->dtpd_provider);
|
38
|
+
return string;
|
39
|
+
}
|
40
|
+
|
41
|
+
/*
|
42
|
+
* Returns the name of the module where the probe is defined.
|
43
|
+
*/
|
44
|
+
VALUE dtraceprobe_mod(VALUE self)
|
45
|
+
{
|
46
|
+
VALUE string;
|
47
|
+
dtrace_probedesc_t *pdp;
|
48
|
+
|
49
|
+
Data_Get_Struct(self, dtrace_probedesc_t, pdp);
|
50
|
+
string = rb_str_new2(pdp->dtpd_mod);
|
51
|
+
return string;
|
52
|
+
}
|
53
|
+
|
54
|
+
/*
|
55
|
+
* Returns the name of the function where the probe is defined.
|
56
|
+
*/
|
57
|
+
VALUE dtraceprobe_func(VALUE self)
|
58
|
+
{
|
59
|
+
VALUE string;
|
60
|
+
dtrace_probedesc_t *pdp;
|
61
|
+
|
62
|
+
Data_Get_Struct(self, dtrace_probedesc_t, pdp);
|
63
|
+
string = rb_str_new2(pdp->dtpd_func);
|
64
|
+
return string;
|
65
|
+
}
|
66
|
+
|
67
|
+
/*
|
68
|
+
* Returns the name of the probe.
|
69
|
+
*/
|
70
|
+
VALUE dtraceprobe_name(VALUE self)
|
71
|
+
{
|
72
|
+
VALUE string;
|
73
|
+
dtrace_probedesc_t *pdp;
|
74
|
+
|
75
|
+
Data_Get_Struct(self, dtrace_probedesc_t, pdp);
|
76
|
+
string = rb_str_new2(pdp->dtpd_name);
|
77
|
+
return string;
|
78
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/* Ruby-Dtrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
RUBY_EXTERN VALUE eDtraceException;
|
8
|
+
RUBY_EXTERN VALUE cDtraceProgramInfo;
|
9
|
+
|
10
|
+
/* :nodoc: */
|
11
|
+
VALUE dtraceprogram_init(VALUE self)
|
12
|
+
{
|
13
|
+
dtrace_prog_t *prog;
|
14
|
+
|
15
|
+
Data_Get_Struct(self, dtrace_prog_t, prog);
|
16
|
+
return self;
|
17
|
+
}
|
18
|
+
|
19
|
+
/*
|
20
|
+
* Execute the D program. Returns a DtraceProgramInfo object if
|
21
|
+
* successful, otherwise raises a DtraceException.
|
22
|
+
*/
|
23
|
+
VALUE dtraceprogram_exec(VALUE self)
|
24
|
+
{
|
25
|
+
dtrace_prog_t *prog;
|
26
|
+
dtrace_proginfo_t *proginfo;
|
27
|
+
dtrace_hdl_t *handle;
|
28
|
+
VALUE dtrace;
|
29
|
+
VALUE dtraceprograminfo;
|
30
|
+
int ret;
|
31
|
+
|
32
|
+
Data_Get_Struct(self, dtrace_prog_t, prog);
|
33
|
+
dtrace = rb_iv_get(self, "@dtrace");
|
34
|
+
Data_Get_Struct(dtrace, dtrace_hdl_t, handle);
|
35
|
+
|
36
|
+
proginfo = ALLOC(dtrace_proginfo_t);
|
37
|
+
ret = dtrace_program_exec(handle, prog, proginfo);
|
38
|
+
|
39
|
+
if (ret == 0) {
|
40
|
+
dtraceprograminfo = Data_Wrap_Struct(cDtraceProgramInfo, 0, NULL, proginfo);
|
41
|
+
rb_iv_set(self, "@proginfo", dtraceprograminfo);
|
42
|
+
}
|
43
|
+
|
44
|
+
if (ret < 0)
|
45
|
+
rb_raise(eDtraceException, dtrace_errmsg(handle, dtrace_errno(handle)));
|
46
|
+
|
47
|
+
return Qnil;
|
48
|
+
}
|
49
|
+
|
50
|
+
/*
|
51
|
+
* Return this program's DtraceProgramInfo object. Returns nil unless
|
52
|
+
* the program has been executed.
|
53
|
+
*/
|
54
|
+
VALUE dtraceprogram_info(VALUE self)
|
55
|
+
{
|
56
|
+
return rb_iv_get(self, "@proginfo");
|
57
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
/* Ruby-Dtrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
/* :nodoc: */
|
8
|
+
VALUE dtraceprograminfo_init(VALUE self)
|
9
|
+
{
|
10
|
+
dtrace_proginfo_t *proginfo;
|
11
|
+
|
12
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
13
|
+
return self;
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Returns the number of aggregates associated with this program.
|
18
|
+
*/
|
19
|
+
VALUE dtraceprograminfo_aggregates_count(VALUE self)
|
20
|
+
{
|
21
|
+
dtrace_proginfo_t *proginfo;
|
22
|
+
|
23
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
24
|
+
return INT2NUM(proginfo->dpi_aggregates);
|
25
|
+
}
|
26
|
+
|
27
|
+
/*
|
28
|
+
* Returns the number of record generating probes associated with this
|
29
|
+
* program.
|
30
|
+
*/
|
31
|
+
VALUE dtraceprograminfo_recgens_count(VALUE self)
|
32
|
+
{
|
33
|
+
dtrace_proginfo_t *proginfo;
|
34
|
+
|
35
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
36
|
+
return INT2NUM(proginfo->dpi_recgens);
|
37
|
+
}
|
38
|
+
|
39
|
+
/*
|
40
|
+
* Returns the number of probes matched by this program.
|
41
|
+
*/
|
42
|
+
VALUE dtraceprograminfo_matches_count(VALUE self)
|
43
|
+
{
|
44
|
+
dtrace_proginfo_t *proginfo;
|
45
|
+
|
46
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
47
|
+
return INT2NUM(proginfo->dpi_matches);
|
48
|
+
}
|
49
|
+
|
50
|
+
/*
|
51
|
+
* Returns the number of speculations specified by this program.
|
52
|
+
*/
|
53
|
+
VALUE dtraceprograminfo_speculations_count(VALUE self)
|
54
|
+
{
|
55
|
+
dtrace_proginfo_t *proginfo;
|
56
|
+
|
57
|
+
Data_Get_Struct(self, dtrace_proginfo_t, proginfo);
|
58
|
+
return INT2NUM(proginfo->dpi_speculations);
|
59
|
+
}
|
60
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
/* Ruby-Dtrace
|
2
|
+
* (c) 2007 Chris Andrews <chris@nodnol.org>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "dtrace_api.h"
|
6
|
+
|
7
|
+
/* :nodoc: */
|
8
|
+
VALUE dtracerecdesc_init(VALUE self)
|
9
|
+
{
|
10
|
+
dtrace_recdesc_t *recdesc;
|
11
|
+
|
12
|
+
Data_Get_Struct(self, dtrace_recdesc_t, recdesc);
|
13
|
+
return self;
|
14
|
+
}
|
15
|
+
|
16
|
+
/*
|
17
|
+
* Return the data for this record.
|
18
|
+
*/
|
19
|
+
VALUE dtracerecdesc_data(VALUE self)
|
20
|
+
{
|
21
|
+
VALUE dtraceaggdata;
|
22
|
+
dtrace_recdesc_t *recdesc;
|
23
|
+
dtrace_aggdata_t *aggdata;
|
24
|
+
|
25
|
+
Data_Get_Struct(self, dtrace_recdesc_t, recdesc);
|
26
|
+
|
27
|
+
dtraceaggdata = rb_iv_get(self, "@aggdata");
|
28
|
+
Data_Get_Struct(dtraceaggdata, dtrace_aggdata_t, aggdata);
|
29
|
+
|
30
|
+
if (recdesc->dtrd_size == 256) {
|
31
|
+
char *c = aggdata->dtada_data + recdesc->dtrd_offset;
|
32
|
+
return rb_str_new2(c);
|
33
|
+
}
|
34
|
+
else {
|
35
|
+
uint64_t n = *((uint64_t *)(aggdata->dtada_data + recdesc->dtrd_offset));
|
36
|
+
return INT2FIX(n);
|
37
|
+
}
|
38
|
+
}
|
data/ext/extconf.rb
ADDED
data/lib/dtrace.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the dtrace plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Generate documentation for the dtrace plugin.'
|
16
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
17
|
+
rdoc.rdoc_dir = 'rdoc'
|
18
|
+
rdoc.title = 'Dtrace'
|
19
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'drb'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
# allow running standalone or in a rails app
|
8
|
+
script_dir = Pathname.new(File.dirname(__FILE__)).realpath
|
9
|
+
rails_script = script_dir + '../vendor/plugins/dtrace/bin'
|
10
|
+
plugin_script = script_dir + '../../../../vendor/plugins/dtrace/bin'
|
11
|
+
if rails_script.directory?
|
12
|
+
rails_root = script_dir + '../'
|
13
|
+
elsif plugin_script.directory?
|
14
|
+
rails_root = script_dir + '../../../..'
|
15
|
+
end
|
16
|
+
$LOAD_PATH << File.join(rails_root + 'vendor/plugins/dtrace/lib')
|
17
|
+
|
18
|
+
require 'dtracer'
|
19
|
+
|
20
|
+
here = "druby://localhost:2999"
|
21
|
+
tracer = Dtracer.new
|
22
|
+
DRb.start_service here, tracer
|
23
|
+
DRb.thread.join
|
24
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'dtracer'
|
2
|
+
require 'dtracer_client'
|
3
|
+
|
4
|
+
module DtraceReport
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend DtraceMacro
|
8
|
+
end
|
9
|
+
|
10
|
+
module DtraceMacro
|
11
|
+
def dtrace(enable=:on, options={})
|
12
|
+
if enable == :on
|
13
|
+
if options[:tracer] == :self
|
14
|
+
DtraceReport.tracer = Dtracer.new
|
15
|
+
elsif options[:tracer] == :helper
|
16
|
+
DtracerReport.tracer = DtracerClient.new
|
17
|
+
else
|
18
|
+
raise "tracer option is self or helper"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :dtrace_report
|
25
|
+
|
26
|
+
protected
|
27
|
+
def self.tracer=(tracer)
|
28
|
+
@@tracer = tracer
|
29
|
+
end
|
30
|
+
|
31
|
+
def enable_dtrace
|
32
|
+
@@tracer.start_dtrace($$)
|
33
|
+
end
|
34
|
+
|
35
|
+
def append_dtrace_report
|
36
|
+
@dtrace_report = @@tracer.end_dtrace
|
37
|
+
# yuck!
|
38
|
+
old_template_root = @template.base_path
|
39
|
+
begin
|
40
|
+
@template.view_paths = File.join(RAILS_ROOT, 'vendor/plugins/dtrace/views')
|
41
|
+
response.body.gsub!(/<\/body/, @template.render(:partial => 'dtrace/report') + '</body')
|
42
|
+
ensure
|
43
|
+
@template.view_paths = old_template_root
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'dtrace'
|
2
|
+
|
3
|
+
class Dtracer
|
4
|
+
|
5
|
+
def start_dtrace(pid)
|
6
|
+
@d = Dtrace.new
|
7
|
+
@d.setopt("aggsize", "4m")
|
8
|
+
@d.setopt("bufsize", "4m")
|
9
|
+
progtext = 'ruby$1:::function-entry{ @[strjoin(strjoin(copyinstr(arg0),"."),copyinstr(arg1))] = count(); }'
|
10
|
+
begin
|
11
|
+
prog = @d.compile(progtext, pid.to_s)
|
12
|
+
prog.execute
|
13
|
+
@d.go
|
14
|
+
rescue DtraceException => e
|
15
|
+
puts "start: #{e.message}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def end_dtrace(pid)
|
20
|
+
begin
|
21
|
+
@d.stop
|
22
|
+
@d.aggregate_snap
|
23
|
+
|
24
|
+
dtrace_report = Hash.new
|
25
|
+
@d.each_aggregate do |agg|
|
26
|
+
dtrace_report[agg[1].data] = agg[2].data
|
27
|
+
end
|
28
|
+
rescue DtraceException => e
|
29
|
+
puts "end: #{e.message}"
|
30
|
+
end
|
31
|
+
|
32
|
+
return dtrace_report
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'dtrace'
|
2
|
+
|
3
|
+
class Dtracer
|
4
|
+
|
5
|
+
def start_dtrace(pid)
|
6
|
+
progtext = 'ruby$1:::function-entry{ @[strjoin(strjoin(copyinstr(arg0),"."),copyinstr(arg1))] = count(); }'
|
7
|
+
|
8
|
+
begin
|
9
|
+
@d = Dtrace.new
|
10
|
+
@d.setopt("aggsize", "4m")
|
11
|
+
@d.setopt("bufsize", "4m")
|
12
|
+
rescue DtraceException => e
|
13
|
+
puts "start setup: #{e.message}"
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
prog = @d.compile(progtext, pid.to_s)
|
19
|
+
prog.execute
|
20
|
+
@d.go
|
21
|
+
rescue DtraceException => e
|
22
|
+
puts "start: #{e.message}"
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_dtrace
|
28
|
+
return {} unless @d
|
29
|
+
|
30
|
+
begin
|
31
|
+
@d.stop
|
32
|
+
@d.aggregate_snap
|
33
|
+
dtrace_report = Hash.new
|
34
|
+
@d.each_aggregate do |agg|
|
35
|
+
dtrace_report[agg[1].data] = agg[2].data
|
36
|
+
end
|
37
|
+
rescue DtraceException => e
|
38
|
+
puts "end: #{e.message}"
|
39
|
+
end
|
40
|
+
|
41
|
+
return dtrace_report
|
42
|
+
end
|
43
|
+
end
|