Skip to content

Conversation

@nvasilevski
Copy link
Contributor

@nvasilevski nvasilevski commented Aug 19, 2025

Context

Rails previously included a monkeypatch that added a ms method to the Benchmark module to return timing results in milliseconds instead of seconds. This monkeypatch has been deprecated in Rails and will be removed in future versions. ref: rails/rails@4cdf757

This commit adds native support for millisecond timing measurements by adding a new Benchmark.ms method
that returns elapsed time in milliseconds.

Reasoning

For web applications, measuring performance in milliseconds is much more helpful since the majority of operations happen in less than a second. While it's acceptable to display times >1s as "1.2s", showing "0.125s" instead of "125ms" is significantly less readable and intuitive for developers analyzing performance metrics.

Examples

Benchmark.realtime { sleep 0.1 }  #=> 0.10023

Benchmark.ms { sleep 0.1 }  #=> 100.23

This change provides a clean migration path for Rails applications currently relying on the deprecated monkeypatch while offering enhanced functionality for all benchmark users.

lib/benchmark.rb Outdated
# #=> 509.8029999935534
#
def realtime(unit = :float_second) # :yield:
r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC, unit)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern here is there might be a non-trivial overhead to pass a variable unit to Process.clock_gettime, which happens with this change. Ruby implementations might optimize it better if the unit is constant.

So I think it would be safer to:

  • Leave realtime untouched
  • Add ms and inline the logic (it's so simple anyway), and it also avoids an extra method call + block call for ms.

Copy link
Member

@eregon eregon Aug 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another use case I know of is to use :nanosecond to avoid any conversion, loss of precision and overhead.
However in that case it's better to just call Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond) directly to avoid an extra method call + block (e.g. in benchmark harnesses like benchmark-ips).
So for that case it wouldn't be the best to use Benchmark.realtime(:nanosecond) { ... } anyway and better to:

start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
...
end = Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
duration_in_ns = end - start

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a fair point! I have no concerns with inlining Process.clock_gettime calls in the ms method. Updated commit & description

@nvasilevski nvasilevski force-pushed the add-ms-function-and-pass-unit-arg-to-realtime branch from b730244 to f5d4ab5 Compare August 20, 2025 13:38
Copy link
Member

@eregon eregon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test? Then I think this is good to go, though it'd be good to get a second review too.

Rails previously included a monkeypatch that added a `ms` method to the
Benchmark module to return timing results in milliseconds instead of
seconds. This monkeypatch has been deprecated in Rails and will be
removed in future versions. ref: rails/rails@4cdf757

This commit adds native support for millisecond timing measurements by adding a new `Benchmark.ms` method
that returns elapsed time in milliseconds.

For web applications, measuring performance in milliseconds is much more helpful since the majority of operations happen in less than a second.
While it's acceptable to display times >1s as "1.2s", showing "0.125s" instead of "125ms" is significantly less readable and intuitive for
developers analyzing performance metrics.

```ruby
Benchmark.realtime { sleep 0.1 }  #=> 0.10023

Benchmark.ms { sleep 0.1 }  #=> 100.23
```

This change provides a clean migration path for Rails applications
currently relying on the deprecated monkeypatch while offering
enhanced functionality for all benchmark users.
@nvasilevski nvasilevski force-pushed the add-ms-function-and-pass-unit-arg-to-realtime branch from f5d4ab5 to 6a3fe1f Compare August 20, 2025 20:33
@hsbt hsbt merged commit fc27ad1 into ruby:master Sep 3, 2025
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants