Skip to content

Revamp benchmark suite with storefront workloads and guarded comparisons - #70

Merged
cappuc merged 11 commits into
mainfrom
feat/bench-update
Jul 30, 2026
Merged

Revamp benchmark suite with storefront workloads and guarded comparisons#70
cappuc merged 11 commits into
mainfrom
feat/bench-update

Conversation

@cappuc

@cappuc cappuc commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replace legacy Shopify fixtures with a realistic file-backed storefront theme.
  • Split benchmarks into default, cache, and operations workload groups.
  • Add profiling reports, storefront coverage tests, and comparison safeguards.
  • Harden CI benchmark filtering, warmup, retry thresholds, and failure handling.

Testing

  • Not run; change request content only.

cappuc and others added 11 commits July 30, 2026 09:43
- ThemeBench read template sources inside the timed loop, so benchTokenize
  and benchParse measured the filesystem: 313us of the ~840us per rev were
  file_get_contents calls. Sources are now read once in setUp.
- The theme used a pluralize filter that does not exist in this library.
  Unknown filters return their input unmodified, so the cart line rendered
  as "Cart: 3 3". Added fixture_pluralize and asserted on the rendered
  output so a missing filter cannot pass silently again.
- The CI segfault exclusion only named benchLoadAndRenderVarExporter, while
  the new benchBuildVarExporter subject ran unfiltered.
- Restored warmup, dropped in the suite revamp. Passing it on the command
  line rather than via attributes keeps the base and PR runs symmetric
  regardless of what the base commit declares.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LiquidBench was the only consumer of the old Shopify theme fixture, so
deleting it left the whole harness unreachable: ThemeRunner, the theme test
template pair, CommentFormTag, PaginateTag, CustomFilters, Database with its
vision.database.yml, and the 34 template files under performance/tests.

symfony/yaml went with Database, its only user, and the phpstan baseline
entries for the removed files are gone too.

DatabaseDrop stays: OperationBench still uses it for the drop benchmarks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Renames the theme to `storefront` (it renders four page types, not one
collection), replaces the fixture's inline data with a typed drop layer, and
deepens the theme into something a real storefront page would look like.

Data layer. `Database` is a typed-drop factory rather than the generic
array-wrapping table store the deleted Shopify harness used: ten drops, one per
entity, no recursive conversion and no phpstan suppressions. Two rules keep the
benchmark measuring the library instead of the fixture — it assigns rather than
computes, and it memoizes nothing, so #[Cache] starts cold on every render and no
state is shared across revolutions. Building the fixture is ~6% of benchRender.

Drop resolution strategies are assigned deliberately, each where a real drop
would use it: public typed properties for stored fields, methods for derived
values, #[Cache] on the one method that walks every variant and is read by three
snippets, and liquidMethodMissing only on metafields, where keys are genuinely
arbitrary. DatabaseDrop is gone and performance/Shopify/ with it.

Theme. Twenty-nine templates across the same four pages: real head metadata,
nested navigation, breadcrumbs, a filter sidebar, a variant picker, a specs
table, a multi-column footer. It now uses the tags a real theme uses — case,
capture, cycle, for/else, break, continue and {% liquid %} — and the fabricated
padding that repeated inventory_label five times per product is gone. Tags real
themes barely touch stay out; they belong in micro subjects.

Verification. Benchmarks run with library defaults, but the fixture test renders
every page with strictVariables, strictFilters and rethrowErrors on, so a missing
variable, filter or swallowed error fails the suite rather than rendering as
empty output. No snapshots: the theme is expected to keep growing, and a
regenerated snapshot asserts nothing.

performance/README.md records the design constraints that are invisible in the
code, and the deferred list — per-tag micro subjects, the drop miss path,
size-parameterized scaling, coverage-only tags, TemplateCacheBench's shape, and
the CI base run's missing --group=macro.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Convention, from the two liquidMethodMissing implementations in src/Drops:
MetafieldsDrop declares #[DropDynamicProperties], so toArray() can see the
dynamic keys. It does not affect Drop::__get resolution.

The eleven-key product row shape was written out twice; it is now one
@phpstan-type, as src/Parse and src/Nodes already do for their shapes.

page_title restated titles that Database entities already owned, in a match
inside StorefrontTheme — which also made that class change for two reasons.
Titles shared by an entity and by the page title now live in one constant each,
and the product title is read from the row rather than from a built drop:
resolving the duplication through Database::product() would have rebuilt all 24
products per render, undoing the construction fix.

Removed ROOT_TEMPLATE_NAME and the default arguments that referenced it — no
caller omitted the argument — and the breadcrumb branch for an empty parent,
which all three call sites passed a literal for.

Corrected three documentation claims that overstated the fixture: the nav is
flat by design rather than nested, #[Cache] is read twice per instance on the
product page rather than by three snippets, and the ~6% fixture-construction
share is a measured reference point with no assertion behind it, so it says how
to re-measure. The deferred list gains the liquidMethodMissing hit path, which
OperationBench stopped covering when its drop was swapped.

Fixture construction re-measured at 6.3% of benchRender.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Scope storefront fixture data and discover templates automatically
- Add operation benchmarks and comparator regression tests
- Enforce a 5% CI regression threshold
@github-actions

Copy link
Copy Markdown
Contributor

PHPBench comparison (PHP 8.3)

Benchmark comparison was not generated.

@github-actions

Copy link
Copy Markdown
Contributor

PHPBench comparison (PHP 8.4)

Benchmark comparison was not generated.

@github-actions

Copy link
Copy Markdown
Contributor

PHPBench comparison (PHP 8.2)

Benchmark comparison was not generated.

@github-actions

Copy link
Copy Markdown
Contributor

PHPBench comparison (PHP 8.5)

Benchmark comparison was not generated.

@cappuc
cappuc merged commit 9913b0e into main Jul 30, 2026
10 of 14 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.

1 participant