Crell / Tukio

A complete and robust implementation of the PSR-14 EventDispatcher specification.
Other
105 stars 6 forks source link

Opt-in optimization for the compiled provider #21

Closed Crell closed 1 year ago

Crell commented 1 year ago

Description

This PR lets the user specify on the ProviderBuilder what events it should optimize. Once we have the class name of those events, we can pre-compute all the listeners that will apply to that event and write out that list directly in the compiled container. That way, those events become an O(1) array lookup.

It also moves most of the callable-creation logic to compile time, which makes the compiled code both smaller and faster.

Motivation and context

Because speed. And an O(1) listener provider is pretty sweet.

How has this been tested?

I think the benchmarks from my computer show the benefits of this approach adequately.

The memory usage is slightly higher, which I think is attributable to the code size of the generated class. For that execution time boost, I think it's absolutely worth it.

+--------------------------------+----------------------+-----+------+-----+----------+----------+--------+
| benchmark                      | subject              | set | revs | its | mem_peak | mode     | rstdev |
+--------------------------------+----------------------+-----+------+-----+----------+----------+--------+
| CompiledProviderBench          | bench_match_provider |     | 50   | 10  | 3.184mb  | 0.1048ms | ±3.62% |
| OptimizedCompiledProviderBench | bench_match_provider |     | 50   | 10  | 4.555mb  | 0.0003ms | ±4.48% |
| OrderedProviderBench           | bench_match_provider |     | 50   | 10  | 2.022mb  | 0.1443ms | ±2.31% |
+--------------------------------+----------------------+-----+------+-----+----------+----------+--------+

The PHPStan checks fail on PHP 7.4 due to the presence of PHP 8 attribute machinery; they don't actually cause a problem because there are checks already to avoid that code path. Since PHP 7.4 is already unsupported and the next major of Tukio will require PHP 8, I don't care about it. The tests pass, and that is enough.

Types of changes

What types of changes does your code introduce? Put an x in all the boxes that apply:

Crell commented 1 year ago

Leaving this here for a bit in case anyone wants to test it...

shulard commented 1 year ago

Hello!

Clever way to optimize event handling!

Regarding optimization have you though adding an annotation to “mark” events so the compiler can discover them all and optimize every event?

For sure with the current change it’s possible to do that manually in the user land.

Crell commented 1 year ago

I had wanted us to include a marker interface in PSR-14, but got overruled by the rest of the working group. This is one of the reasons I wanted it. 😢

Even if you had a marker interface, you'd need to know what directories to scan for classes that have that interface. (And then string parse the files so you don't have to load all the code into memory at once.) And if you're already doing that, you may as well just have a directory with known events (as many frameworks already do), and auto-register everything in that directory. Such an auto-scanner isn't hard (I've written one for a few other projects), but out of scope for the moment.

I'm open to adding such ability in the future, but I am not sure where the line should be between the library's responsibility and the framework's responsibility.