`
CharlesCui
  • 浏览: 431259 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Ruby Benchmark的实现

阅读更多
以我们常用的benchmark方法bm()为例,

请看下面这个例子:
    Benchmark.bm(20) do |x|
      x.report("getBWIL"){1000.times{result.getBindedWebIdList(0, '22000005')}}
      x.report("getBWIL"){5000.times{result.getBindedWebIdList(0, '22000005')}}
      x.report("getBWIL"){10000.times{result.getBindedWebIdList(0, '22000005')}}
    end


  def bm(label_width = 0, *labels, &blk) # :yield: report
    benchmark(" "*label_width + CAPTION, label_width, FMTSTR, *labels, &blk)
  end

可以看到,源码里它是调用了benchmark方法,跳到benchmark

  def benchmark(caption = "", label_width = nil, fmtstr = nil, *labels) # :yield: report
    sync = STDOUT.sync
    STDOUT.sync = true
    label_width ||= 0
    fmtstr ||= FMTSTR
    raise ArgumentError, "no block" unless iterator?
    print caption
    results = yield(Report.new(label_width, fmtstr))
    Array === results and results.grep(Tms).each {|t|
      print((labels.shift || t.label || "").ljust(label_width), 
            t.format(fmtstr))
    }
    STDOUT.sync = sync
  end

这里的代码我们只看yield,这就是例子中的那个传递给bm的block的x,是个Report对象。

  class Report # :nodoc:
    #
    # Returns an initialized Report instance.
    # Usually, one doesn't call this method directly, as new
    # Report objects are created by the #benchmark and #bm methods. 
    # _width_ and _fmtstr_ are the label offset and 
    # format string used by Tms#format. 
    # 
    def initialize(width = 0, fmtstr = nil)
      @width, @fmtstr = width, fmtstr
    end

    #
    # Prints the _label_ and measured time for the block,
    # formatted by _fmt_. See Tms#format for the
    # formatting rules.
    #
    def item(label = "", *fmt, &blk) # :yield:
      print label.ljust(@width)
      res = Benchmark::measure(&blk)
      print res.format(@fmtstr, *fmt)
      res
    end

    alias report item
  end

进入Report后发现,x.report其实就是Report.item,item方法中关键的实现是Benchmark::measure,继续跟进

  def measure(label = "") # :yield:
    t0, r0 = Benchmark.times, Time.now
    yield
    t1, r1 = Benchmark.times, Time.now
    Benchmark::Tms.new(t1.utime  - t0.utime, 
                       t1.stime  - t0.stime, 
                       t1.cutime - t0.cutime, 
                       t1.cstime - t0.cstime, 
                       r1.to_f - r0.to_f,
                       label)
  end


这里看到benchmark中真正负责计算执行时间的算法,很容易理解,但有个关键的类型要知道,Benchmark.times,我们继续走进看看这个东东是什么。

插一句,我们上面看到的measure方法前面并没有加self关键字来定义,为何就变成了模块方法可以Benchmark::measure直接执行呢,原因在benchmark.rb文件第353行:
module_function :benchmark, :measure, :realtime, :bm, :bmbm

module_function将模块内方法变成了模块方法(java的静态方法),可以通过模块名直接引用的。

  def Benchmark::times() # :nodoc:
      Process::times()
  end

Benchmark.times调用了Process::times(),继续走进

  #     Process.times   => aStructTms
  #
  #
  # Returns a <code>Tms</code> structure (see <code>Struct::Tms</code>
  # on page 388) that contains user and system CPU times for this
  # process.
  #
  #    t = Process.times
  #    [ t.utime, t.stime ]   #=> [0.0, 0.02]
  #
  #
  def self.times
    # This is just a stub for a builtin Ruby method.
    # See the top of this file for more info.
  end


我们跳进了另一个文件stub_process.rb,看到这个东东的E文说明,是builtin方法,native code不下ruby的源文件是看不到源码的,看说明我们知道这个方法返回Tms结构体。

tms这个结构体在ruby中没有说明,但可以在Linux的内核文件中找到定义,
请参看<sys/times.h>

struct tms {
     clock_t  tms_utime;  /* user CPU time */
     clock_t  tms_stime;  /* system CPU time */
     clock_t  tms_cutime; /* user CPU time, terminated children */
     clock_t  tms_cstime; /* system CPU time, terminated children */
   };


该结构体是针对当前进程而得到的结果,
tms_utime是用户态时间,我们写的ruby的代码执行时间应该算在这里,
tms_stime是系统态时间,应该是启动或者销毁ruby解析器所花费的时间,还有其它和系统相关的任务所花费的时间。
剩下的两个children的我就不知道了,是不是该进程所起动的子进程的当前用户态和系统态时间?可能。

benchmark的计时算法就是把这四个时间相减,得到block的执行时间,再用Time.now相减,得到real time.

ruby中通过以下方法访问tms结构体:
utime           # user time
stime           # system time
cutime          # user time of children
cstime          # system time of children

分享到:
评论
1 楼 Hooopo 2009-08-31  

刚才翻了一下benchmark,发现了这个bmbm..

# * The times for some benchmarks depend on the order in which items
#   are run.  These differences are due to the cost of memory


#   allocation and garbage collection. To avoid these discrepancies,
#   the #bmbm method is provided.  For example, to compare ways to
#   sort an array of floats:
#
#       require 'benchmark'
#       
#       array = (1..1000000).map { rand }
#       
#       Benchmark.bmbm do |x|
#         x.report("sort!") { array.dup.sort! }
#         x.report("sort")  { array.dup.sort  }
#       end
# 
#   The result:
# 
#        Rehearsal -----------------------------------------
#        sort!  11.928000   0.010000  11.938000 ( 12.756000)
#        sort   13.048000   0.020000  13.068000 ( 13.857000)
#        ------------------------------- total: 25.006000sec
#        
#                    user     system      total        real
#        sort!  12.959000   0.010000  12.969000 ( 13.793000)
#        sort   12.007000   0.000000  12.007000 ( 12.791000)

相关推荐

    Ruby编程,实用程序员指南Programming Ruby, The Pragmatic Programmer's Guide

    - **线程(Thread)**:Ruby支持多线程编程,可以轻松实现并发任务处理。 - **进程(Process)**:除了线程之外,还可以使用进程来实现更高级别的并发。 ### 四、Ruby生态系统 #### 4.1 RubyGems - **包管理器**:...

    Ruby-性能测试(完整版)

    - `Benchmark`: Ruby内置的基准测试库,用于简单的性能比较,可以测量代码执行时间。 - `ruby-prof`: 提供更详细的性能分析,包括调用树和内存分配信息。 - `cProfile`: 对于MRI(Ruby的默认实现)的C扩展,可以...

    Ruby使用心得汇总——寻找高效的实现

    在Ruby中,`Benchmark`模块允许我们衡量代码执行的时间,以便于比较不同实现的性能。例如,通过对比`gsub`和`tr`方法替换字符串中的特定字符,我们可以发现`tr`方法在效率上优于`gsub`,这对于大量处理字符串的场景...

    Ruby Developer Guide

    了解如何定义类、创建对象、实现继承、模块导入以及封装和多态性是学习Ruby的基础。 3. **块、 Proc 和 Lambda**:Ruby中的块、Proc和Lambda是函数式编程的重要概念,它们可以捕获上下文,作为参数传递,并且可以被...

    ruby-kaigi-notes-源码.rar

    源码中可能涉及如何在 Ruby 中有效地实现并发,避免常见的并发问题。 6. **错误调试与日志**:有效的错误处理和日志记录是任何项目的关键部分。笔记可能会讲解如何利用 Ruby 的调试工具,以及如何设计良好的日志...

    Ruby Best Practices

    - 利用Ruby的块、 Proc 和 Lambda 来实现函数式编程的特性,使代码更简洁。 3. **异常处理** - 尽量避免使用`rescue`来捕获所有异常,而应尽可能具体,只捕获预期的错误类型。 - 使用`ensure`块来确保在发生异常...

    ruby-http-clients:一些针对各种ruby库的基准测试代码

    Ruby HTTP客户端 这是我的ruby http客户端库的基准。...我很乐意在这里加入更多客户,或者解决我的实现中的所有问题。 bin /基准 $ bin/benchmark --help Usage: bin/benchmark [options] URL -n, --number N Run

    optcarrot:用Ruby编写的NES模拟器

    Optcarrot:适用于Ruby Benchmark的NES仿真器项目目标该项目旨在为Ruby实现提供一个“令人愉快的”基准,以推动 。 具体目标是一个NES(任天堂娱乐系统)仿真器,该仿真器在Ruby 2.0中以20 fps的速度工作。 原始NES...

    ruby_1_9_3_stdlib

    Ruby 1.9.3 是 Ruby 语言的一个重要版本,发布于2011年,它的标准库(stdlib)...开发者可以根据需要选择并利用这些模块和类,以实现各种复杂的任务。理解并熟练运用 Ruby 的标准库,是提高编程效率和代码质量的关键。

    ruby-tools-开源

    6. **性能分析**:提供性能基准测试和优化建议,例如使用 Benchmark 或 Bullet 库来识别和消除 N+1 查询或其他性能瓶颈。 7. **文档生成**:可能包含自动生成 API 文档的工具,如 YARD,使得代码的可读性和维护性更...

    algorithms_and_data_structures.rb:Ruby中算法,数据结构和HackerRank解决方案的实现

    Ruby中的算法和数据结构实现。 对Ruby的表现力着迷和好奇,该存储库包含我对基本CS概念的实现以及其他HackerRank解决方案。在线评估您可能会偶然发现包含该行语句评估的内联注释,例如ary = [ 1 , 2 , 3 , 4 ]ary # ...

    eventing-hyperfoil-benchmark

    同时,Vert.x提供了多种语言API,包括JavaScript、Ruby、Groovy等,增强了跨语言协作的能力。 总结来说,"eventing-hyperfoil-benchmark"项目是针对CloudEvents处理性能的基准测试,通过Hyperfoil发送模拟事件,...

    fast-rsa-engine:该gem通过更快的实现替换了jruby-openssl的RSA签名密码

    用于jruby-openssl gem的快速RSA引擎 该gem通过必须更快地实现的方式替换了jruby-openssl的RSA签名和RSA密码。... ruby benchmark/benchmark-with-fast-rsa.rb 或ruby基准/基准-内置-rsa.rb 发展 将所有的宝石和罐子放

    Ruby Meta Programming: define_method or class_eval

    为了比较`define_method`和`class_eval`的性能差异,`time_dsl_benchmark.rb`文件可能包含了使用rBench工具进行的基准测试。rBench是一个简单的性能测试工具,它可以帮助开发者评估不同实现的运行时间。通过分析这个...

    hash_benchmark:对不同的 C 哈希进行基准测试

    对 MRI 的哈希实现进行基准测试这个实验的目的是对 MRI 的哈希表实现与其他实现进行基准测试,看看它是否可以改进。 现在有三个竞争者: st (不是与 Ruby 捆绑在一起的修改版,因为我还不能让它工作。) uthash...

    edn_turbo:edn-ruby插件,使用基于Ragel的C ++实现替换了ruby解析器

    基于Ruby的基于的快速EDN解析器。 edn_turbo可以用作的解析器插件。 除了少数例外, edn_turbo提供了与edn gem相同的功能,但是由于edn_turbo解析器是用C ++实现的,因此速度要快一个数量级。 一些快速示例运行以...

    ProgrammingRuby:学习Ruby基础知识

    方法是实现代码重用的关键,Ruby支持定义和调用方法。块是Ruby的独特特性,类似于其他语言中的匿名函数,可以与方法一起使用,常用于迭代器。 4. **异常处理** 在Ruby中,可以使用`begin-rescue-end`来捕获和处理...

    every_ruby_talk_ever:当我刚开始使用Ruby时,我疯狂观看了会议演讲,以求进步。 这是我的一些注意事项。

    6. **性能优化**:探讨Ruby和Rails应用的性能瓶颈,以及如何使用Benchmark、Profiler等工具进行性能分析和优化。 通过"every_ruby_talk_ever",你可以学习到这些主题的深度见解和实践经验,不断提升你的Ruby和Rails...

    RubyLearning:关于Ruby语言的实践

    - 性能优化:了解Ruby的性能瓶颈,如对象创建、GC(垃圾回收)等,并使用Benchmark模块进行性能测试。 - 社区与文档:积极参与Ruby社区,利用GitHub、Stack Overflow和RubyDoc等资源学习和解决问题。 6. **领域...

    RubyLabPattern

    10. **并发与多线程**:Ruby中的线程并不等同于其他语言,理解Thread和Fiber的区别,以及如何在Ruby中实现并发和并行。 通过深入研究RubyLabPattern项目,开发者不仅可以深化对Ruby语言的理解,还能掌握在实际项目...

Global site tag (gtag.js) - Google Analytics