Skip to content

[StimulusBundle] Speed up Stimulus name normalization - #3781

Merged
Kocal merged 1 commit into
symfony:3.xfrom
Kocal:perf/stimulus-bundle-name-normalization
Aug 18, 2026
Merged

[StimulusBundle] Speed up Stimulus name normalization#3781
Kocal merged 1 commit into
symfony:3.xfrom
Kocal:perf/stimulus-bundle-name-normalization

Conversation

@Kocal

@Kocal Kocal commented Aug 15, 2026

Copy link
Copy Markdown
Member
Q A
Bug fix? no
New feature? no
Deprecations? no
Documentation? no
Issues -
License MIT

normalizeKeyName() ran three preg_* calls for every value, class and param name, and normalizeControllerName() ran a preg_replace() for every controller name. Both run on every stimulus_controller() / stimulus_action() call, on names that repeat across the whole page.

Memoize the key names (a fixed set coming from templates and controllers) and drop the regex from the controller name, which only strips a leading @.

Rendering 50k controllers with values, classes, an action and a target goes from ~414 ms to ~356 ms. On a more realistic page though, an admin CRUD page with 100 Stimulus controllers, that's 0.45 ms -> 0.42 ms per page: a 7% cut on a budget that's already under a millisecond. smnandre asked in review whether the project should have a minimum gain worth accepting, given the maintenance and history cost of a change like this. That's a fair question: this is a small, low-risk win, not a big one, and reviewers should weigh it as such rather than as more than it is.

Benchmarked from the repository root with blackfire run symfony php bench.php:

<?php
require __DIR__.'/src/StimulusBundle/vendor/autoload.php';

use Symfony\UX\StimulusBundle\Dto\StimulusAttributes;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

$env = new Environment(new ArrayLoader([]));

for ($i = 0; $i < 5000; ++$i) {
    $attributes = new StimulusAttributes($env);
    $attributes->addController('my-controller', ['name' => 'ryan', 'isEnabled' => true, 'count' => 42], ['loading' => 'spinner']);
    $attributes->addAction('my-controller', 'onClick', 'click');
    $attributes->addTarget('my-controller', 'element');
    (string) $attributes;
}

Blackfire:

Analysis, implementation and benchmarks by Claude Opus 5.

@Kocal Kocal self-assigned this Aug 15, 2026
@Kocal
Kocal requested review from kbond and smnandre August 15, 2026 05:30

@smnandre smnandre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we define a minimum gap to accept improvements ?

There is a hidden cost in maintenance, history, etc.

Genuine question, I have no opinion here :)

@carsonbot carsonbot added Status: Reviewed Has been reviewed by a maintainer and removed Status: Needs Review Needs to be reviewed labels Aug 15, 2026
@Kocal
Kocal force-pushed the perf/stimulus-bundle-name-normalization branch 2 times, most recently from 7d573ee to cf6ceac Compare August 15, 2026 22:14
| Q              | A
| -------------- | ---
| Bug fix?       | no
| New feature?   | no
| Deprecations?  | no
| Documentation? | no
| Issues         | -
| License        | MIT

`normalizeKeyName()` ran three `preg_*` calls for every value, class and
param name, and `normalizeControllerName()` a `preg_replace()` for every
controller name. Both run on every `stimulus_controller()` /
`stimulus_action()` call, on names that repeat across the whole page.

Memoize the key names (a fixed set coming from templates and controllers)
and drop the regex from the controller name, which only strips a leading
`@`.

Rendering 50k controllers with values, classes, an action and a target:
~414 ms -> ~356 ms.

Benchmarked from the repository root with `blackfire run symfony php bench.php`:

```php
<?php
require __DIR__.'/src/StimulusBundle/vendor/autoload.php';

use Symfony\UX\StimulusBundle\Dto\StimulusAttributes;
use Twig\Environment;
use Twig\Loader\ArrayLoader;

$env = new Environment(new ArrayLoader([]));

for ($i = 0; $i < 5000; ++$i) {
    $attributes = new StimulusAttributes($env);
    $attributes->addController('my-controller', ['name' => 'ryan', 'isEnabled' => true, 'count' => 42], ['loading' => 'spinner']);
    $attributes->addAction('my-controller', 'onClick', 'click');
    $attributes->addTarget('my-controller', 'element');
    (string) $attributes;
}
```

Blackfire:

- before — 833ms wall / 816ms CPU: https://app.blackfire.io/envs/5f4f9a62-eaa0-45ee-b7b3-a1b879f550e9/profiles/4d6d06bc-f658-4786-952a-302cc8c852ec/graph
- after — 632ms wall / 628ms CPU: https://app.blackfire.io/envs/5f4f9a62-eaa0-45ee-b7b3-a1b879f550e9/profiles/c56f1954-74f2-40ad-9514-eab58bcb8912/graph
- diff: https://app.blackfire.io/envs/5f4f9a62-eaa0-45ee-b7b3-a1b879f550e9/profiles/compare/4d6d06bc-f658-4786-952a-302cc8c852ec...c56f1954-74f2-40ad-9514-eab58bcb8912/graph

Analysis, implementation and benchmarks by Claude Opus 5.
@Kocal
Kocal force-pushed the perf/stimulus-bundle-name-normalization branch from cf6ceac to 267c77e Compare August 15, 2026 22:21
@Kocal

Kocal commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Should we define a minimum gap to accept improvements ?

There is a hidden cost in maintenance, history, etc.

Genuine question, I have no opinion here :)

Before AI, I'd say we had to be careful with performance patches when it came to code readability, but now I think it's fine... The code is still easy to read IMHO

@Kocal
Kocal merged commit cb3af3c into symfony:3.x Aug 18, 2026
32 of 33 checks passed
@Kocal
Kocal deleted the perf/stimulus-bundle-name-normalization branch August 18, 2026 05:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Performance Status: Reviewed Has been reviewed by a maintainer StimulusBundle

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants