2

開発中のコードをテストするための小さなベンチマーク クラスを作成しました。現時点では、すべてのメソッドの最初と最後にクラスを追加する必要があります。コードを乱雑にする必要がないように、その場で先頭に追加したり、追加したりすることは可能ですか?

class ApplicationController    
    before_filter :init_perf
    after_filter :write_perf_results_to_log!

    def init_perf
      @perf ||= Perf.new
    end

    def write_perf_results_to_log!
      @perf.results
    end
end

class Products < ApplicationsController    
    def foo      
      @perf.log(__methond__.to_s)
      caculation = 5 *4
      @perf.write! 
    end

    def bar      
      @perf.log(__methond__.to_s)
      caculation = 1 / 5
      @perf.write! 
    end
end

これがPerfクラスです。サービスフォルダにあります。

class Perf
  def initialize
    @results = []
  end

  def log(note)
    @start = Time.now
    @note = note
  end

  def write!
    if @results.find {|h| h[:note] == @note } # Update :sec method exists in results 
      @results.select { |h| h["note"] == @note; h[":sec"] = (Time.now - @start).round(3) }
    else # Add new Hash to results
      @results << { :note => @note, :sec => (Time.now - @start).round(3) }
    end
  end

  def results
    content = "
    PERFORMANCE STATISTICS!
    "
    @results.each do |r|
      content += r[:note] + "   " + r[:sec].to_s + "
      "
    end
    content += "
    "
    Rails.logger.info content
  end
end
4

4 に答える 4

5

一般的なコンピューティング用語では、実行したいことをコード インスツルメンテーションと呼びます。これを実現するにはいくつかの方法がありますが、メタプログラミングを使用した (粗雑な) 例を次に示します。

最初に、インストルメンテーション コードを挿入するために使用する新しいメソッドを定義します。

class ApplicationController
  def self.instrument_methods(*methods)
    methods.each { |m|
      # Rename original method
      self.send(:alias_method, "#{m}_orig", m)

      # Redefine old method with instrumentation code added
      define_method m do
        puts "Perf log #{m}"
        self.send "#{m}_orig"
        puts "Perf write"
      end
    }
  end
end

それの使い方:

class Product < ApplicationController
  def foo
    puts "Foo"
  end

  def bar
    puts "Bar"
  end

  # This has to be called last, once the original methods are defined
  instrument_methods :foo, :bar
end

それで:

p = Product.new
p.foo
p.bar

出力します:

Perf log foo
Foo
Perf write
Perf log bar
Bar
Perf write

Ruby コードを計測してパフォーマンスを測定する他の方法を次に示します。

http://ruby-prof.rubyforge.org/
http://www.igvita.com/2009/06/13/profiling-ruby-with-googles-perftools/

于 2013-01-18T10:58:56.277 に答える
2

私はアスペクト宝石の作者です。言及してくれてありがとう。

私はアスペクトを使用して解決策を考え出しました。大まかな手順は次のとおりです。

  1. Aspector::Base のサブクラスとしてアスペクトを作成する
  2. アスペクト内で、アドバイスを定義します (前/後/前後が主な種類のアドバイスです)。
  3. ターゲット クラス (またはモジュール/オブジェクト) にアスペクトを適用します。

完全なコードは、この gistにあります。ご不明な点がある場合、または解決策が意図したとおりに機能しない場合は、お気軽にお知らせください。

class PerfAspect < Aspector::Base
  options[:action_methods] do |proxy| 周辺
    @perf ||= Perf.new
    プロキシ呼び出し
    @perf.結果
  終わり

  周囲のオプション[:other_methods], :method_arg => true do |method, proxy, *args, &block|
    @perf.log(メソッド)
    result = proxy.call *args, &block
    @perf.write!
    結果
  終わり
終わり

action_methods = [:アクション]
other_methods = Products.instance_methods(false) - action_methods

PerfAspect.apply(製品、:action_methods => action_methods、:other_methods => other_methods)
于 2013-01-23T22:44:19.650 に答える
2

より良い解決策があります。

class ApplicationController
    def self.inherited(klass)
        def klass.method_added(name)
            return if @_not_new
            @_not_new = true
            original = "original #{name}"
            alias_method original, name
            define_method(name) do |*args, &block|
                puts "==> called #{name} with args: #{args.inspect}"
                result = send original, *args, &block
                puts "<== result is #{result}"
                result
            end
            @_not_new = false
        end
    end
end

class Product < ApplicationController

    def meth(a1, a2)
        a1 + a2
    end
end

product = Product.new
puts product.meth(2,3)

そして結果:

==> called meth with args: [2, 3]
<== result is 5
5

ソースと説明はこちら: http://pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming . このコースを受講するために多額の費用をかけないことをお勧めします。

于 2013-01-18T16:38:17.660 に答える
1

アスペクトの宝石が役立つと思います。十分に文書化されていませんが、役立つ例があります。

于 2013-01-18T10:58:10.367 に答える