Back to Mruby

mruby-benchmark

mrbgems/mruby-benchmark/README.md

4.0.05.9 KB
Original Source

mruby-benchmark

Benchmarking and profiling tools for mruby.

Overview

The mruby-benchmark gem provides simple and lightweight benchmarking capabilities for measuring execution time and memory usage in mruby applications. It is designed for embedded systems and resource-constrained environments.

Installation

Add the following line to your build_config.rb:

ruby
conf.gem :core => 'mruby-benchmark'

API

Benchmark Module

The main interface for benchmarking operations.

Benchmark.measure { block } → Benchmark::Tms

Measures the execution time of the given block and returns a Benchmark::Tms object containing timing information.

ruby
result = Benchmark.measure do
  # code to benchmark
  1000.times { "string interpolation: #{42}" }
end

puts result  # Prints formatted timing information

Benchmark.realtime { block } → Float

Returns only the real (wall-clock) time in seconds as a floating-point number.

ruby
time = Benchmark.realtime do
  sleep(0.1)
end

puts "Took #{time} seconds"  # => "Took 0.100... seconds"

Benchmark.bm(label_width = 0) { |x| ... }

Performs formatted benchmark comparisons with aligned output.

ruby
Benchmark.bm(10) do |x|
  x.report("array:") { 1000.times { [1, 2, 3, 4, 5] } }
  x.report("hash:") { 1000.times { {a: 1, b: 2, c: 3} } }
  x.report("string:") { 1000.times { "hello" * 100 } }
end

Output example:

                user     system      total        real
array:      0.010000   0.000000   0.010000 (  0.012345)
hash:       0.015000   0.000000   0.015000 (  0.016789)
string:     0.008000   0.000000   0.008000 (  0.009012)

Benchmark.measure(memory: true) { block } → Benchmark::Tms

Measures both execution time and memory allocation when memory: true is specified.

ruby
result = Benchmark.measure(memory: true) do
  array = []
  1000.times { |i| array << i }
end

puts "Objects allocated: #{result.objects}"
puts "Memory used: #{result.memory} bytes"

Benchmark::Tms Class

Holds timing measurement results. Provides methods to access individual timing components.

Attributes

  • utime - User CPU time in seconds (Float)
  • stime - System CPU time in seconds (Float)
  • cutime - User CPU time of child processes (Float, usually 0 in mruby)
  • cstime - System CPU time of child processes (Float, usually 0 in mruby)
  • real - Real (wall-clock) time in seconds (Float)
  • objects - Number of objects allocated (Integer, when memory tracking enabled)
  • memory - Memory allocated in bytes (Integer, when memory tracking enabled)

Methods

total → Float

Returns the total CPU time (user + system).

ruby
result = Benchmark.measure { heavy_computation }
puts "Total CPU time: #{result.total} seconds"
to_s → String

Returns formatted string representation of timing results.

ruby
result = Benchmark.measure { sleep(0.1) }
puts result.to_s
# => "  0.000000   0.000000   0.000000 (  0.100123)"
format(format_str) → String

Returns timing results formatted according to the format string.

Format specifiers:

  • %u - User CPU time
  • %s - System CPU time
  • %t - Total CPU time
  • %r - Real time
  • %o - Objects allocated (if memory tracking enabled)
  • %m - Memory allocated (if memory tracking enabled)
  • %n - Label name
ruby
result = Benchmark.measure { computation }
puts result.format("Real: %rs, CPU: %ts")
# => "Real: 0.123s, CPU: 0.100s"

Benchmark::Report Class

Used within Benchmark.bm for formatted reporting.

report(label = "") { block }

Executes and reports on a single benchmark within a bm block.

ruby
Benchmark.bm do |x|
  x.report("first test") { code1 }
  x.report("second test") { code2 }
end

Usage Examples

Basic Timing

ruby
require 'benchmark'

# Simple timing
time = Benchmark.realtime do
  sum = 0
  1000000.times { |i| sum += i }
end
puts "Calculation took #{time} seconds"

# Detailed timing
result = Benchmark.measure do
  arr = (1..10000).to_a
  arr.sort!
end
puts result

Comparing Implementations

ruby
require 'benchmark'

Benchmark.bm(15) do |x|
  x.report("Array#each:") do
    arr = (1..1000).to_a
    sum = 0
    arr.each { |n| sum += n }
  end

  x.report("Array#inject:") do
    arr = (1..1000).to_a
    arr.inject(0) { |sum, n| sum + n }
  end

  x.report("Numeric#times:") do
    sum = 0
    1000.times { |n| sum += n }
  end
end

Memory Profiling

ruby
require 'benchmark'

# Track memory allocation
result = Benchmark.measure(memory: true) do
  strings = []
  1000.times { |i| strings << "string_#{i}" }
end

puts "Execution time: #{result.real}s"
puts "Objects created: #{result.objects}"
puts "Memory allocated: #{result.memory} bytes"

Performance Testing in Tests

ruby
# In test files
assert('String concatenation performance') do
  time = Benchmark.realtime do
    1000.times { "hello" + "world" }
  end

  # Assert it completes within reasonable time
  assert_true time < 0.1, "String concat should be fast"
end

Implementation Notes

Time Measurement

mruby-benchmark uses Process.clock_gettime (via mruby-time) for high-resolution timing when available. User and system CPU times are measured using platform-specific APIs where available, otherwise both are set to 0.

Memory Tracking

Memory profiling uses ObjectSpace.count_objects (via mruby-objectspace) to track object allocation. Memory size estimation is based on typical object overhead and may not be exact for all platforms.

Limitations

  • Child process timing (cutime, cstime) is not supported in most mruby environments and always returns 0
  • System CPU time may not be available on all platforms
  • Memory measurements are estimates and may not reflect actual heap usage
  • GC activity during benchmarking may affect timing results

Dependencies

  • mruby-time - Required for timing measurements
  • mruby-objectspace - Required for memory profiling

License

MIT License

Authors

mruby developers