XPerf
LanguagesRuby

Ruby performance guide (v0)

Fewer quadratic builders, quieter hot paths.

Scope: MRI Ruby 3+. Speedup claims cite a local bench, an upstream source, or are marked provisional. Corpus residual counts are lint hit counts, not wall-time savings.

Profile first (benchmark, stackprof). JRuby and TruffleRuby differ — re-bench.

Contents

1. Strings, arrays, and hashes

s += piece allocates a new string each time; prefer s << piece (or a buffer). arr = arr + [x] copies; prefer << / push.

Hash#merge in a loop was removed. On Ruby 4.0.8 the suggested literal build was slower than merge (~0.78×, and again ~0.65×) and allocated about twice as many objects. See evidence/_removed/rb-hash-merge-in-loop.REMOVED.md.

Lint: rb-string-plus-hot, rb-array-plus-rebind (default off).

2. Hot I/O

puts / print in a tight loop flushes. Gate debug output or buffer.

Lint: rb-puts-hot (default off).

3. Compile and parse

Regexp.new compiles on every call. A regexp literal is cached. JSON.parse / generate on a fixed payload repeats the parse. A changing payload cannot be hoisted. These lints are hint and have a microbench. Date.parse / Time.parse / DateTime.parse was removed for the same reason as a fixed-string parse: the after side only wins by not parsing.

File.read of one path was about 346× versus reading once. File.open is the same lint. A path that changes every iteration cannot be hoisted. Process.clock_gettime was about 2.3× and send about 1.9×; those were checked and not given a rule.

Lint: rb-regexp-new-hot, rb-json-hot, rb-file-read-hot (default hint).

Lint map

IDSmellDefault
rb-string-plus-hotstring += in loopoff
rb-array-plus-rebindArray + / concat rebinding in loopoff
rb-puts-hotputs / print in loopoff
rb-regexp-new-hotRegexp.new in loophint (measured; not corpus-triaged)
rb-json-hotJSON.parse / generate in loophint (measured; not corpus-triaged)

Enable an off rule with --severity <rule>=hint. Escalate to error only with measured evidence/rb-*.jsonl — see evidence-policy.md. rb-date-parse-in-loop and rb-hash-merge-in-loop were removed.

References