[前][次][番号順一覧][スレッド一覧]

ruby-changes:51375

From: normal <ko1@a...>
Date: Wed, 6 Jun 2018 06:30:27 +0900 (JST)
Subject: [ruby-changes:51375] normal:r63581 (trunk): test/dtrace/helper.rb: support systemtap in dtrace tests

normal	2018-06-06 06:19:50 +0900 (Wed, 06 Jun 2018)

  New Revision: 63581

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63581

  Log:
    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.

  Modified files:
    trunk/test/dtrace/helper.rb
Index: test/dtrace/helper.rb
===================================================================
--- test/dtrace/helper.rb	(revision 63580)
+++ test/dtrace/helper.rb	(revision 63581)
@@ -10,6 +10,22 @@ elsif (sudo = ENV["SUDO"]) and !sudo.emp https://github.com/ruby/ruby/blob/trunk/test/dtrace/helper.rb#L10
 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 https://github.com/ruby/ruby/blob/trunk/test/dtrace/helper.rb#L36
     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 https://github.com/ruby/ruby/blob/trunk/test/dtrace/helper.rb#L73
       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 https://github.com/ruby/ruby/blob/trunk/test/dtrace/helper.rb#L130
       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 https://github.com/ruby/ruby/blob/trunk/test/dtrace/helper.rb#L153
 
 if ok
   DTrace::TestCase.class_variable_set(:@@sudo, sudo)
+  DTrace::TestCase.const_set(:IMPL, impl)
+  DTrace::TestCase.const_set(:RUBYBIN, rubybin)
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]