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