| name | performance |
| description | This skill should be used when the user asks about "Ruby performance", "optimization", "profiling", "benchmarking", "memory", "garbage collection", "GC", "benchmark-ips", "stackprof", "memory_profiler", "slow code", "speed up Ruby", or needs guidance on making Ruby code faster. |
| version | 1.0.0 |
Ruby Performance Optimization
Guide to profiling, benchmarking, and optimizing Ruby code.
Profiling First
Always measure before optimizing. Identify bottlenecks with profiling tools.
benchmark-ips
Compare implementations with statistical significance:
require "benchmark/ips"
Benchmark.ips do |x|
x.report("map + flatten") do
[[1, 2], [3, 4]].map { |a| a * 2 }.flatten
end
x.report("flat_map") do
[[1, 2], [3, 4]].flat_map { |a| a * 2 }
end
x.compare!
end
stackprof (CPU Profiling)
require "stackprof"
StackProf.run(mode: :cpu, out: "tmp/stackprof.dump") do
1000.times { expensive_operation }
end
memory_profiler
require "memory_profiler"
report = MemoryProfiler.report do
data = process_large_dataset
end
report.pretty_print
Memory Optimization
Reduce Object Allocations
def bad_join(items)
result = ""
items.each do |item|
result = result + item.to_s + ", "
end
result
end
def good_join(items)
result = +""
items.each do |item|
result << item.to_s << ", "
end
result
end
items.join(", ")
Frozen String Literals
name = "Alice"
Symbol vs String
hash = { name: "Alice", age: 30 }
hash = { "user_input" => value }
Lazy Enumerables
File.readlines("large.txt").select { |l| l.include?("ERROR") }.first(10)
File.foreach("large.txt")
.lazy
.select { |l| l.include?("ERROR") }
.first(10)
Object Pooling
class ConnectionPool
def initialize(size:)
@available = Array.new(size) { create_connection }
@mutex = Mutex.new
end
def with_connection
conn = checkout
yield conn
ensure
checkin(conn)
end
private
def checkout
@mutex.synchronize { @available.pop }
end
def checkin(conn)
@mutex.synchronize { @available.push(conn) }
end
def create_connection
end
end
Algorithm Optimization
Choose Right Data Structures
require "set"
array = [1, 2, 3, 4, 5]
array.include?(3)
set = Set[1, 2, 3, 4, 5]
set.include?(3)
hash = { 1 => true, 2 => true, 3 => true }
hash.key?(3)
Avoid N+1 in Ruby Code
users.each do |user|
user.orders.each do |order|
end
end
orders_by_user = orders.group_by(&:user_id)
users.each do |user|
user_orders = orders_by_user[user.id] || []
end
Memoization
class ExpensiveCalculator
def result
@result ||= compute_expensive_result
end
def calculate(n)
@cache ||= {}
@cache[n] ||= expensive_computation(n)
end
def clear_cache!
@result = nil
@cache = nil
end
end
Garbage Collection
Understanding GC
GC.stat
GC.start
GC.disable
GC.enable
Reduce GC Pressure
def bad_process(items)
items.map { |i| i.to_s }
.map { |s| s.upcase }
.map { |s| s.strip }
end
def good_process(items)
items.map { |i| i.to_s.upcase.strip }
end
def best_process(items)
items.each do |i|
end
end
GC Tuning Environment Variables
RUBY_GC_HEAP_INIT_SLOTS=600000
RUBY_GC_MALLOC_LIMIT=64000000
RUBY_GC_HEAP_GROWTH_FACTOR=1.25
Warning: GC tuning values should be determined through profiling your specific application. Avoid cargo-cult optimization by copying values without understanding your application's memory patterns. Always measure before and after tuning.
Concurrency
Threads for I/O
require "concurrent"
pool = Concurrent::ThreadPoolExecutor.new(
min_threads: 5,
max_threads: 10,
max_queue: 100
)
urls.each do |url|
pool.post do
fetch_url(url)
end
end
pool.shutdown
pool.wait_for_termination
Ractors for CPU
ractors = data.each_slice(data.size / 4).map do |chunk|
Ractor.new(chunk) do |items|
items.map { |item| expensive_computation(item) }
end
end
results = ractors.flat_map(&:take)
Async for I/O
require "async"
Async do
results = urls.map do |url|
Async do
fetch_url(url)
end
end.map(&:wait)
end
Common Optimizations
String Building
result = ""
items.each { |i| result += i.to_s }
result = items.map(&:to_s).join
io = StringIO.new
items.each { |i| io << i.to_s }
result = io.string
Array Operations
array.any? { |x| x > 5 }
array.all? { |x| x > 5 }
array.find { |x| x > 5 }
array.count > 0
array.any?
array.select { ... }.first
array.find { ... }
Hash Operations
hash.fetch(:key, default_value)
hash.fetch(:key) { compute_default }
hash.transform_keys(&:to_sym)
hash.transform_values(&:to_s)
hash.merge!(other_hash)
Additional Resources
Reference Files
references/profiling-guide.md - Detailed profiling workflows and tool usage