performance
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.
What this skill does
# 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:
```ruby
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
# Output:
# flat_map: 1234567.8 i/s
# map + flatten: 987654.3 i/s - 1.25x slower
```
### stackprof (CPU Profiling)
```ruby
require "stackprof"
StackProf.run(mode: :cpu, out: "tmp/stackprof.dump") do
# Code to profile
1000.times { expensive_operation }
end
# View results
# $ stackprof tmp/stackprof.dump --text
# $ stackprof tmp/stackprof.dump --method 'YourClass#method'
```
### memory_profiler
```ruby
require "memory_profiler"
report = MemoryProfiler.report do
# Code to analyze
data = process_large_dataset
end
report.pretty_print
# Shows allocated objects, retained objects, memory by gem/file/location
```
## Memory Optimization
### Reduce Object Allocations
```ruby
# Bad: Creates many intermediate objects
def bad_join(items)
result = ""
items.each do |item|
result = result + item.to_s + ", " # Creates new strings each time
end
result
end
# Good: Modify in place
def good_join(items)
result = +"" # Unfrozen empty string
items.each do |item|
result << item.to_s << ", "
end
result
end
# Best: Use built-in
items.join(", ")
```
### Frozen String Literals
```ruby
# frozen_string_literal: true
# All string literals are now frozen (immutable)
# Reduces memory by reusing string objects
name = "Alice" # Frozen, shared across uses
```
### Symbol vs String
```ruby
# Symbols are interned (shared in memory)
# Good for hash keys, identifiers
hash = { name: "Alice", age: 30 } # Symbol keys
# Strings are mutable, not shared
# Good for user data, content
hash = { "user_input" => value }
```
### Lazy Enumerables
```ruby
# Bad: Loads entire file into memory
File.readlines("large.txt").select { |l| l.include?("ERROR") }.first(10)
# Good: Processes line by line, stops early
File.foreach("large.txt")
.lazy
.select { |l| l.include?("ERROR") }
.first(10)
```
### Object Pooling
```ruby
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
# Expensive connection creation
end
end
```
## Algorithm Optimization
### Choose Right Data Structures
```ruby
require "set"
# O(n) lookup
array = [1, 2, 3, 4, 5]
array.include?(3) # Slow for large arrays
# O(1) lookup
set = Set[1, 2, 3, 4, 5]
set.include?(3) # Fast
# O(1) lookup with value
hash = { 1 => true, 2 => true, 3 => true }
hash.key?(3) # Fast
```
### Avoid N+1 in Ruby Code
```ruby
# Bad: O(n*m) - nested iteration
users.each do |user|
user.orders.each do |order|
# O(n*m) iterations
end
end
# Better: Pre-group data
orders_by_user = orders.group_by(&:user_id)
users.each do |user|
user_orders = orders_by_user[user.id] || []
# O(n) + O(m) iterations
end
```
### Memoization
```ruby
class ExpensiveCalculator
def result
@result ||= compute_expensive_result
end
# For methods with arguments
def calculate(n)
@cache ||= {}
@cache[n] ||= expensive_computation(n)
end
# Clear cache when needed
def clear_cache!
@result = nil
@cache = nil
end
end
```
## Garbage Collection
### Understanding GC
```ruby
# Check GC stats
GC.stat
# => { count: 42, heap_allocated_pages: 100, ... }
# Manual GC (usually not needed)
GC.start
# Disable during benchmarks (not in production)
GC.disable
# ... run benchmark ...
GC.enable
```
### Reduce GC Pressure
```ruby
# Bad: Many short-lived objects
def bad_process(items)
items.map { |i| i.to_s }
.map { |s| s.upcase }
.map { |s| s.strip }
end
# Good: Chain operations, fewer intermediates
def good_process(items)
items.map { |i| i.to_s.upcase.strip }
end
# Best: Modify in place when possible
def best_process(items)
items.each do |i|
# Modify i in place if possible
end
end
```
### GC Tuning Environment Variables
```bash
# Increase heap slots (reduce GC frequency)
# Note: These values are examples. Profile your application first
# and adjust based on actual memory usage patterns.
RUBY_GC_HEAP_INIT_SLOTS=600000
# Increase malloc limit before GC
RUBY_GC_MALLOC_LIMIT=64000000
# Growth factor for heap
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
```ruby
require "concurrent"
# Thread pool for I/O-bound work
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
```ruby
# True parallelism for CPU-bound work
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
```ruby
require "async"
Async do
results = urls.map do |url|
Async do
fetch_url(url)
end
end.map(&:wait)
end
```
## Common Optimizations
### String Building
```ruby
# Bad
result = ""
items.each { |i| result += i.to_s }
# Good
result = items.map(&:to_s).join
# Also good for large strings
io = StringIO.new
items.each { |i| io << i.to_s }
result = io.string
```
### Array Operations
```ruby
# Use appropriate methods
array.any? { |x| x > 5 } # Stops at first match
array.all? { |x| x > 5 } # Stops at first failure
array.find { |x| x > 5 } # Returns first match
# Avoid repeated operations
# Bad
array.count > 0 # Counts all elements
# Good
array.any? # Stops immediately
# Bad
array.select { ... }.first
# Good
array.find { ... }
```
### Hash Operations
```ruby
# Use fetch with default
hash.fetch(:key, default_value)
hash.fetch(:key) { compute_default }
# Transform keys/values efficiently
hash.transform_keys(&:to_sym)
hash.transform_values(&:to_s)
# Merge in place
hash.merge!(other_hash) # Modifies hash
```
## Additional Resources
### Reference Files
- **`references/profiling-guide.md`** - Detailed profiling workflows and tool usage
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.