summaryrefslogtreecommitdiff
path: root/test/dtrace/helper.rb
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-06-05 21:19:50 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-06-05 21:19:50 +0000
commit750f1a39882910dd6357550e2187c264e3d7f0b5 (patch)
treef7eb47147560c5657f59a2b8c867144ed5a6a95c /test/dtrace/helper.rb
parentbd80fc53159f4ada3549b6f85209af13be375095 (diff)
test/dtrace/helper.rb: support systemtap in dtrace tests
For the current cases, a few string substitions is enough to make dtrace(1) scripts work with stap(1). For more complex scripts (maybe in the future), we may pass a hash with implementation-specific scripts. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63581 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'test/dtrace/helper.rb')
-rw-r--r--test/dtrace/helper.rb86
1 files changed, 80 insertions, 6 deletions
diff --git a/test/dtrace/helper.rb b/test/dtrace/helper.rb
index de971a3b09..023d1165b4 100644
--- a/test/dtrace/helper.rb
+++ b/test/dtrace/helper.rb
@@ -10,6 +10,22 @@ elsif (sudo = ENV["SUDO"]) and !sudo.empty? and (`#{sudo} echo ok` rescue false)
else
ok = false
end
+
+impl = :dtrace
+
+# GNU/Linux distros with Systemtap support allows unprivileged users
+# in the stapusr and statdev groups to work.
+if RUBY_PLATFORM =~ /linux/
+ impl = :stap
+ begin
+ require 'etc'
+ login = Etc.getlogin
+ ok = Etc.getgrnam('stapusr').mem.include?(login) &&
+ Etc.getgrnam('stapdev').mem.include?(login)
+ rescue LoadError, ArgumentError
+ end unless ok
+end
+
if ok
case RUBY_PLATFORM
when /darwin/i
@@ -20,7 +36,24 @@ if ok
end
end
end
-ok &= (`dtrace -V` rescue false)
+
+# use miniruby to reduce the amount of trace data we don't care about
+rubybin = "miniruby#{RbConfig::CONFIG["EXEEXT"]}"
+rubybin = File.join(File.dirname(EnvUtil.rubybin), rubybin)
+rubybin = EnvUtil.rubybin unless File.executable?(rubybin)
+
+# make sure ruby was built with --enable-dtrace and we can run
+# dtrace(1) or stap(1):
+cmd = "#{rubybin} --disable=gems -eexit"
+case impl
+when :dtrace; cmd = %W(dtrace -l -n ruby$target:::gc-sweep-end -c #{cmd})
+when :stap; cmd = %W(stap -l process.mark("gc__sweep__end") -c #{cmd})
+else
+ warn "don't know how to check if built with #{impl} support"
+ cmd = false
+end
+ok &= system(*cmd, err: IO::NULL, out: IO::NULL) if cmd
+
module DTrace
class TestCase < Test::Unit::TestCase
INCLUDE = File.expand_path('..', File.dirname(__FILE__))
@@ -40,17 +73,52 @@ module DTrace
end
end
+ # only handles simple cases, use a Hash for d_program
+ # if there are more complex cases
+ def dtrace2systemtap(d_program)
+ translate = lambda do |str|
+ # dtrace starts args with '0', systemtap with '1' and prefixes '$'
+ str = str.gsub(/\barg(\d+)/) { "$arg#{$1.to_i + 1}" }
+ # simple function mappings:
+ str.gsub!(/\bcopyinstr\b/, 'user_string')
+ str.gsub!(/\bstrstr\b/, 'isinstr')
+ str
+ end
+ out = ''
+ cond = nil
+ d_program.split(/^/).each do |l|
+ case l
+ when /\bruby\$target:::([a-z-]+)/
+ name = $1.gsub(/-/, '__')
+ out << %Q{probe process.mark("#{name}")\n}
+ when %r{/(.+)/}
+ cond = translate.call($1)
+ when "{\n"
+ out << l
+ out << "if (#{cond}) {\n" if cond
+ when "}\n"
+ out << "}\n" if cond
+ out << l
+ else
+ out << translate.call(l)
+ end
+ end
+ out
+ end
+
DTRACE_CMD ||= %w[dtrace]
READ_PROBES ||= proc do |cmd|
IO.popen(cmd, err: [:child, :out], &:readlines)
end
- miniruby = "miniruby#{RbConfig::CONFIG["EXEEXT"]}"
- miniruby = File.join(File.dirname(EnvUtil.rubybin), miniruby)
- RUBYBIN = File.exist?(miniruby) ? miniruby : EnvUtil.rubybin
-
def trap_probe d_program, ruby_program
+ if Hash === d_program
+ d_program = d_program[IMPL] or
+ skip "#{d_program} not implemented for #{IMPL}"
+ elsif String === d_program && IMPL == :stap
+ d_program = dtrace2systemtap(d_program)
+ end
d = Tempfile.new(%w'probe .d')
d.write d_program
d.flush
@@ -62,7 +130,11 @@ module DTrace
d_path = d.path
rb_path = rb.path
cmd = "#{RUBYBIN} --disable=gems -I#{INCLUDE} #{rb_path}"
- cmd = [*DTRACE_CMD, "-q", "-s", d_path, "-c", cmd ]
+ if IMPL == :stap
+ cmd = %W(stap #{d_path} -c #{cmd})
+ else
+ cmd = [*DTRACE_CMD, "-q", "-s", d_path, "-c", cmd ]
+ end
if sudo = @@sudo
[RbConfig::CONFIG["LIBPATHENV"], "RUBY", "RUBYOPT"].each do |name|
if name and val = ENV[name]
@@ -81,4 +153,6 @@ end if ok
if ok
DTrace::TestCase.class_variable_set(:@@sudo, sudo)
+ DTrace::TestCase.const_set(:IMPL, impl)
+ DTrace::TestCase.const_set(:RUBYBIN, rubybin)
end