Repository navigation
Run lobsters with a fixed clock - #571
Open
thomasklemm wants to merge 1 commit into
Open
thomasklemm wants to merge 1 commit into
thomasklemm wants to merge 1 commit into
Conversation
thomasklemm
force-pushed
the
thomasklemm/lobsters-fixed-clock
branch
from
November 5, 2026 20:25
1e5933c to
b63e9d8
Compare
Lobsters' work per iteration changed with the calendar date: in its US Central time zone, lookbacks such as 70.days.ago that cross a DST change make ActiveSupport look up the zone period again, and two dates switch the logo. Time.now now returns a fixed instant in July, from which no lookback (up to 90 days) crosses a DST change. Harness code outside the benchmark block, including harnesses that HARNESS=chain loads late, keeps the real clock. TRACK_AR_TIME measures with the monotonic clock.
thomasklemm
force-pushed
the
thomasklemm/lobsters-fixed-clock
branch
from
November 5, 2026 20:32
b63e9d8 to
33e9aa4
Compare
thomasklemm
marked this pull request as ready for review
November 5, 2026 21:08
thomasklemm
added a commit
to thomasklemm/ruby-bench
that referenced
this pull request
Nov 6, 2026
The Rails benchmarks here mostly read. None of them submits forms, fails a validation, or runs after-commit callbacks and broadcasts; lobsters' only writes are its read-ribbon bookkeeping. Real apps spend much of their time saving records: validations, callbacks, transactions, INSERT/UPDATE/DELETE and enqueuing jobs. The app is Sam Ruby's create-blog from roundhouse-rb/roundhouse (MIT): rails new --css tailwind on Rails 8.1.4.1, with Article and Comment scaffolds, validations and Turbo broadcasts. It keeps the production defaults of rails new: SQLite, Solid Cache, Solid Queue, Solid Cable, Propshaft and importmap, no external services. The built Tailwind CSS is checked in, so no CSS build runs. benchmarks/blog/README.md lists the few changes to the generated tree. Each iteration runs 200 seeded visits in-process, like railsbench: reads (index, show, JSON) and writes (create, update and delete articles, add and delete comments, a create that fails validation with 422). Writes submit the CSRF token from the page's form, as a browser does, and every response's status is checked, along with a body marker or the redirect target. The iteration runs in one transaction per database that is rolled back at the end, as in Rails tests, so every iteration sees the same rows and IDs. Time.now is fixed while the app runs, as proposed for lobsters in ruby#571. Saves run as savepoints inside that transaction, and their after-commit callbacks run when the savepoint is released, as in Rails tests. Solid Cable inserts each broadcast in the request rather than on its batching writer thread, so it lands in the transaction; the later broadcasts are enqueued into Solid Queue. Since nothing commits, a real COMMIT is not measured.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This fixes
Time.nowin lobsters at 2026-07-01 12:00 UTC, during boot and in the benchmark block, to keep its work per iteration from depending on the date it runs. #572 is an alternative that fixes the clock at a different instant; merge one of the two.On main, in lobsters' US Central time zone, when a lookback such as
70.days.agocrosses a DST change, ActiveSupport looks up the zone period again: 1,476 extra lookups per pass on 2026-11-05, none in July. On Dec 25 and Jun 28 the logo changes too. With the clock fixed, the tzinfo lookup counts were the same on every tested date.Across the four tested dates, allocations per iteration varied by 0.01%, against 1.37% on main (Ruby 4.0.9, system clock set to each date):
Response bodies are byte-identical between runs on 2026-11-05 and 2027-01-20, apart from CSRF tokens. The harness keeps the real clock.
Date.today,DateTime.now,Time.newwithout arguments and SQLite's'now'stay live. Cache entries and the session no longer age.TRACK_AR_TIMEuses the monotonic clock.For lobsters' history this is a one-time step of up to −1.35% objects against runs whose lookbacks cross a DST change (roughly November to January and mid-March to mid-June).
How this was measured
Objects:
GC.stat(:total_allocated_objects)around each iteration of the default harness,WARMUP_ITRS=1 MIN_BENCH_ITRS=3, mean of the 3 measured iterations per date, spread = (max − min) / min of the per-date means, system clock set with libfaketime (FAKETIME='@<date> 12:00:00' FAKETIME_DONT_FAKE_MONOTONIC=1), cg_harness.rb withCG_DUMP=0. Responses: raw_dump.rb writes status, headers and body of all 114 requests in the pass after one warmup pass; raw_cmp.rb blanks theauthenticity_tokenvalues, thecsrf-tokenmeta tag and the random headers (session cookie, ETag, X-Request-Id, X-Runtime) and compares the rest byte for byte: 0 of 114 differ. Lookups: dst_probe.rb.