ruby-dtrace 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,4 @@
1
+ require 'mkmf'
2
+ $CFLAGS += " -D_LONGLONG_TYPE"
3
+ have_library("dtrace", "dtrace_open")
4
+ create_makefile("dtrace_api")
data/lib/dtrace.rb ADDED
@@ -0,0 +1,11 @@
1
+ #
2
+ # Ruby-Dtrace
3
+ # (c) 2007 Chris Andrews <chris@nodnol.org>
4
+ #
5
+
6
+ require 'dtrace_api'
7
+
8
+ class Dtrace
9
+ VERSION = '0.0.1'
10
+ end
11
+
@@ -0,0 +1,4 @@
1
+ Dtrace
2
+ ======
3
+
4
+ Description goes here
@@ -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,7 @@
1
+ require 'dtrace_report'
2
+ ActionController::Base.class_eval do
3
+ include DtraceReport
4
+ before_filter :enable_dtrace if RAILS_ENV == 'development'
5
+ after_filter :append_dtrace_report if RAILS_ENV == 'development'
6
+ end
7
+
@@ -0,0 +1,2 @@
1
+ module DtraceHelper
2
+ end
@@ -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