class Minitest::Benchmark

继承 Benchmark 以创建您自己的基准测试运行。以“bench_”开头的方法将在每个类上执行。

请参阅 Minitest::Assertions

公共类方法

bench_exp(min, max, base = 10) 点击以切换源代码

返回一组范围,这些范围从 minmaxbase 的幂指数方式递增。例如

bench_exp(2, 16, 2) # => [2, 4, 8, 16]
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 35
def self.bench_exp min, max, base = 10
  min = (Math.log10(min) / Math.log10(base)).to_i
  max = (Math.log10(max) / Math.log10(base)).to_i

  (min..max).map { |m| base ** m }.to_a
end
bench_linear(min, max, step = 10) 点击以切换源代码

返回一组范围,这些范围从 minmaxstep 线性递增。例如

bench_linear(20, 40, 10) # => [20, 30, 40]
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 48
def self.bench_linear min, max, step = 10
  (min..max).step(step).to_a
end
bench_range() 点击以切换源代码

指定用于该类的基准测试的范围。默认为从 1 到 10k 以 10 的幂指数增长。如果您需要不同的基准测试范围,请覆盖此方法。

另请参阅:::bench_exp::bench_linear

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 59
def self.bench_range
  bench_exp 1, 10_000
end

公共实例方法

assert_performance(validation, &work) 点击以切换源代码

运行给定的 work,收集每次运行的时间。然后将范围和时间传递给给定的 validation proc。输出基准测试名称和时间,以制表符分隔的格式,使其易于粘贴到电子表格中进行绘图或进一步分析。

范围由 ::bench_range 指定。

例如

def bench_algorithm
  validation = proc { |x, y| ... }
  assert_performance validation do |n|
    @obj.algorithm(n)
  end
end
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 81
def assert_performance validation, &work
  range = self.class.bench_range

  io.print self.name

  times = []

  range.each do |x|
    GC.start
    t0 = Minitest.clock_time
    instance_exec(x, &work)
    t = Minitest.clock_time - t0

    io.print "\t%9.6f" % t
    times << t
  end
  io.puts

  validation[range, times]
end
assert_performance_constant(threshold = 0.99, &work) 点击以切换源代码

运行给定的 work 并断言收集的时间符合给定的 threshold 内的常数速率(例如,线性斜率 == 0)。注意:因为我们正在测试斜率为 0,所以 R^2 不是拟合的良好决定因素,因此阈值会应用于斜率本身。因此,您可能需要从默认值收紧它。

有关更多详细信息,请参阅 www.graphpad.com/guides/prism/8/curve-fitting/reg_intepretingnonlinr2.htm

拟合由 fit_linear 计算。

范围由 ::bench_range 指定。

例如

def bench_algorithm
  assert_performance_constant 0.9999 do |n|
    @obj.algorithm(n)
  end
end
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 125
def assert_performance_constant threshold = 0.99, &work
  validation = proc do |range, times|
    a, b, rr = fit_linear range, times
    assert_in_delta 0, b, 1 - threshold
    [a, b, rr]
  end

  assert_performance validation, &work
end
assert_performance_exponential(threshold = 0.99, &work) 点击以切换源代码

运行给定的 work 并断言收集的时间符合给定的误差 threshold 内的指数曲线。

拟合由 fit_exponential 计算。

范围由 ::bench_range 指定。

例如

def bench_algorithm
  assert_performance_exponential 0.9999 do |n|
    @obj.algorithm(n)
  end
end
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 151
def assert_performance_exponential threshold = 0.99, &work
  assert_performance validation_for_fit(:exponential, threshold), &work
end
assert_performance_linear(threshold = 0.99, &work) 点击以切换源代码

运行给定的 work 并断言收集的时间符合给定的误差 threshold 内的直线。

拟合由 fit_linear 计算。

范围由 ::bench_range 指定。

例如

def bench_algorithm
  assert_performance_linear 0.9999 do |n|
    @obj.algorithm(n)
  end
end
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 191
def assert_performance_linear threshold = 0.99, &work
  assert_performance validation_for_fit(:linear, threshold), &work
end
assert_performance_logarithmic(threshold = 0.99, &work) 点击以切换源代码

运行给定的 work 并断言收集的时间符合给定的误差 threshold 内的对数曲线。

拟合由 fit_logarithmic 计算。

范围由 ::bench_range 指定。

例如

def bench_algorithm
  assert_performance_logarithmic 0.9999 do |n|
    @obj.algorithm(n)
  end
end
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 171
def assert_performance_logarithmic threshold = 0.99, &work
  assert_performance validation_for_fit(:logarithmic, threshold), &work
end
assert_performance_power(threshold = 0.99, &work) 点击以切换源代码

运行给定的 work 并断言收集的时间曲线拟合符合给定的误差 threshold 内的幂曲线。

拟合由 fit_power 计算。

范围由 ::bench_range 指定。

例如

def bench_algorithm
  assert_performance_power 0.9999 do |x|
    @obj.algorithm
  end
end
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 211
def assert_performance_power threshold = 0.99, &work
  assert_performance validation_for_fit(:power, threshold), &work
end
fit_error(xys) { |x| ... } 点击以切换源代码

获取 x/y 对的数组并计算一般的 R^2 值。

请参阅:en.wikipedia.org/wiki/Coefficient_of_determination

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 220
def fit_error xys
  y_bar  = sigma(xys) { |_, y| y } / xys.size.to_f
  ss_tot = sigma(xys) { |_, y| (y    - y_bar) ** 2 }
  ss_err = sigma(xys) { |x, y| (yield(x) - y) ** 2 }

  1 - (ss_err / ss_tot)
end
fit_exponential(xs, ys) 点击以切换源代码

要拟合函数形式:y = ae^(bx)。

获取 x 和 y 值并返回 [a, b, r^2]。

请参阅:mathworld.wolfram.com/LeastSquaresFittingExponential.html

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 235
def fit_exponential xs, ys
  n     = xs.size
  xys   = xs.zip ys
  sxlny = sigma(xys) { |x, y| x * Math.log(y) }
  slny  = sigma(xys) { |_, y| Math.log(y)     }
  sx2   = sigma(xys) { |x, _| x * x           }
  sx    = sigma xs

  c = n * sx2 - sx ** 2
  a = (slny * sx2 - sx * sxlny) / c
  b = ( n * sxlny - sx * slny ) / c

  return Math.exp(a), b, fit_error(xys) { |x| Math.exp(a + b * x) }
end
fit_linear(xs, ys) 点击以切换源代码

拟合函数形式:a + bx。

获取 x 和 y 值并返回 [a, b, r^2]。

请参阅:mathworld.wolfram.com/LeastSquaresFitting.html

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 279
def fit_linear xs, ys
  n   = xs.size
  xys = xs.zip ys
  sx  = sigma xs
  sy  = sigma ys
  sx2 = sigma(xs)  { |x|   x ** 2 }
  sxy = sigma(xys) { |x, y| x * y  }

  c = n * sx2 - sx**2
  a = (sy * sx2 - sx * sxy) / c
  b = ( n * sxy - sx * sy ) / c

  return a, b, fit_error(xys) { |x| a + b * x }
end
fit_logarithmic(xs, ys) 点击以切换源代码

要拟合函数形式:y = a + b*ln(x)。

获取 x 和 y 值并返回 [a, b, r^2]。

请参阅:mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 257
def fit_logarithmic xs, ys
  n     = xs.size
  xys   = xs.zip ys
  slnx2 = sigma(xys) { |x, _| Math.log(x) ** 2 }
  slnx  = sigma(xys) { |x, _| Math.log(x)      }
  sylnx = sigma(xys) { |x, y| y * Math.log(x)  }
  sy    = sigma(xys) { |_, y| y                }

  c = n * slnx2 - slnx ** 2
  b = ( n * sylnx - sy * slnx ) / c
  a = (sy - b * slnx) / n

  return a, b, fit_error(xys) { |x| a + b * Math.log(x) }
end
fit_power(xs, ys) 点击以切换源代码

要拟合函数形式:y = ax^b。

获取 x 和 y 值并返回 [a, b, r^2]。

请参阅:mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 301
def fit_power xs, ys
  n       = xs.size
  xys     = xs.zip ys
  slnxlny = sigma(xys) { |x, y| Math.log(x) * Math.log(y) }
  slnx    = sigma(xs)  { |x   | Math.log(x)               }
  slny    = sigma(ys)  { |   y| Math.log(y)               }
  slnx2   = sigma(xs)  { |x   | Math.log(x) ** 2          }

  b = (n * slnxlny - slnx * slny) / (n * slnx2 - slnx ** 2)
  a = (slny - b * slnx) / n

  return Math.exp(a), b, fit_error(xys) { |x| (Math.exp(a) * (x ** b)) }
end
sigma(enum, &block) 点击以切换源代码

迭代 enum,如果给定 block,则映射 block,返回结果的总和。例如

sigma([1, 2, 3])                # => 1 + 2 + 3 => 6
sigma([1, 2, 3]) { |n| n ** 2 } # => 1 + 4 + 9 => 14
# File minitest-5.25.4/lib/minitest/benchmark.rb, line 322
def sigma enum, &block
  enum = enum.map(&block) if block
  enum.sum
end
validation_for_fit(msg, threshold) 点击以切换源代码

返回一个 proc,该 proc 调用指定的拟合方法并断言误差在可容忍的阈值内。

# File minitest-5.25.4/lib/minitest/benchmark.rb, line 331
def validation_for_fit msg, threshold
  proc do |range, times|
    a, b, rr = send "fit_#{msg}", range, times
    assert_operator rr, :>=, threshold
    [a, b, rr]
  end
end