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.
@@ -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