complate / complate-stream

complate's core library for rendering HTML via JSX
https://complate.org
6 stars 7 forks source link

Improve encode performance #52

Closed tmehnert closed 2 years ago

tmehnert commented 2 years ago

Hi. I have looked at issue #1 and find out that the current htmlEncode can be improved in performance. First i have tried to include html-entities, which will work but i was not brave enogh to include it, because it bundles a lot of stuff into the views bundle. Also htmlEncode is a public API of the library and i don't wanted to change it's produced encoding, because it might break user tests. So i ended up by creating a "own" implementation again, to speed things up.

Micro-Benchmarks

The speed improvement highly depends on the input and the underlying javascript engine. I have prepared some micro-benchmarks for you, that shows the new version should be faster. Just click to run it, these benchmarks will only run the htmlEncode function with some input.

Complate-cpp Benchmarks

I have also run complate-cpp rendering benchmarks with the current and the optimized implementation. I'm using a Intel i7-12700KF which runs an Ubuntu 20.04 on WSL2. All results are mean values of all iterations, i have taken best of five runs each, rounded to one decimal.

Test Current Optimized
QuickJS, no todos 92.7 us 60.0 us
QuickJS, 10 todos 1.2 ms 771.1 us
QuickJS, 100 todos 11.5 ms 7.5 ms
V8, no todos 10.7 us 9.1 us
V8, 10 todos 149.4 us 123.0 us
V8, 100 todos 1.44 ms 1.26 ms

To run the complate-cpp benchmarks by yourself on Linux, assuming you have the dependencies installed on your system.

mkdir build
cd build
cmake -DBUILD_TESTS=on ..
make
test/lib/complate-tests QuickJsRendererBenchmark
test/lib/complate-tests V8RendererBenchmark
tmehnert commented 2 years ago

I have done a new version based on the algorithm of html-entities. I would really like to present you a easy oneliner, but it seems to that the loop based version deliver more stable performance across various engines.

Complate-Cpp Benchmarks

I ran the Benchmarks again with our new algorithms. Loop-Based is the one i have commited.

Test Without Fastpath Loop-Based
QuickJS, no todos 66.4 us 61.3 us
QuickJS, 10 todos 828.5 us 773.8.1 us
QuickJS, 100 todos 8.0 ms 7.5 ms
V8, no todos 9.6 us 9.0 us
V8, 10 todos 138.1 us 125.2 us
V8, 100 todos 1.37 ms 1.21 ms

I have also updated the online benchmark.

tmehnert commented 2 years ago

@FND what is your opinion on that?

FND commented 2 years ago

As noted earlier, I've tweaked a few details in a5830ea2cfc7c0b3adc5e8458e47a0aaaf644105 (see commit message); if you're fine with that, I think this is ready to go.

tmehnert commented 2 years ago

Your change looks good to me, the names are much more better. I ran all my tests and all have passed. The bechmark shows a little drop on QuickJs (0.4ms @ 100 todos), not noticeable on other engines. But with what we achieved, this seems to me irrelevant.

I agree, let's take this nice profit. 👍

FND commented 2 years ago

✅ Squashed as fb7fd6bbbf1b70dc554418eef75301e9d117e75b and released as v0.16.10.

I'm surprised there's a difference to the previous version, but that's just me idly wondering whether that's just chance - but yeah, negligible either way.

Thank you.