News #3:
purust is now way closer to the official JS backend: 484ms → 190ms (vs JS: 125ms)
Still a lot to do. But that’s getting cool.
News #3:
purust is now way closer to the official JS backend: 484ms → 190ms (vs JS: 125ms)
Still a lot to do. But that’s getting cool.
News #4:
All right! We’ve fallen below the official JS backend threshold (i.e., 125ms), with a total of 119ms.
To be continued ![]()
News #5:
Arista
(81ms)
Scheme
(46ms)
Benchmark here.
Of course, the final major step of cleaning up what was co-produced with AI still remains. But since I’ve already started that process with gopurs, it should go smoothly. For now, I’m continuing to dig deeper and deeper, to see how far we can go (which is much faster now that almost all optimization techniques have been tested with gopurs: I can directly reproduce them).
News #6:
Finally happened: purust (21ms) is now ahead of gopurs (24ms)…
The Koka-n way of life is giving good results.
I haven’t mentioned this backend yet, because I don’t want to take over the forum, but javapurs is the new champion of the benchmark (for now): the new goal is to reach its metrics. Happily, there’s still things to do… (e.g., finish the Perceus plan, which is still only modestly addressed).
An exhaustive (and a bit dirty) progress table is available here. The goal is to get white/green everywhere in the first 5 columns. The first lines are prioritized.
News #8:
I’m not going to ask an AI to check my English in this post. Not this time. Pure joy takes over.
For the first time, a backend is close to reach the highly symbolic 10-millisecond barrier. It might not quite make it, but the mere fact that it’s so close is amazing in itself: purust (12ms) is now “far” ahead of gopurs (24ms, twice as fast!) and javapurs (17ms). The closer you get to 0, the more each millisecond feels as a victory.
Is this a “Eureka!” moment? Perhaps something akin to an Act II for PureScript? That’s how I feel about it, personally.
The benchmarks aren’t perfect, nor are the numbers, nor is the code. In fact, nothing really is. The lab is a mess, and the to-do list is a mile long. I’m aware of this, and I thank everyone following these developments for their patience and tolerance in the face of the imperfections left by my AI-copiloted experiments. I’m aware they exist. Above all, I’ll remember your support and enthusiasm.
I’m trying to maximize the reach of the momentum and clear the ground as best I can before tackling precision engineering. Even though I don’t currently hold any official position, my time and energy remain fairly limited, as I have other important commitments on the side (volunteering, moving, getting started with job seeking, etc.).
But the essentials are in place.
The chemical reaction finally seems to be working without altering the two compounds: Rust’s speed is preserved, as is PureScript’s concise and pure expressiveness.
And of course, the doors of crates swing wide open: leverage a low-level ecosystem that is both rich and easily accessible.
Next steps: official tests, module-by-module tests (e.g., Aff), real-world conditions, etc.
Edit #1: pscpp seems to take 9.5ms, that’s my next goal.
Edit #2: #1 turned out to be false
News #9:
The heavy lifting for Aff support in purust is done, and it works wonderfully. I’m really happy with the result. Tests 100% green (e.g. purust-aff) ![]()
Under the hood, purust-aff is natively built on top of tokio (using its multi-thread capabilities). That’s rather similar to what’s been done with goroutines for gopurs.
This gives us full native support for the entire async API: Fork, ParApply, Sequential, Fiber cancellation, Bracket for safe resource management, etc. (lots of things).
There are still tiny details to fix, but this will be pushed soon. The surrounding ecosystem (like purust-js-promise and purust-js-promise-aff) still needs to be ported. And as usual, a cleanup will need to be done at the end.
I’ll test that soon, via a benchmark which is mainly dedicated to concurrent/parallel metrics.
Also: I’m currently trying to get tests green on a real-world project (website here). I’ll see how it handles the FFI and the Aff spec test suites.
News #10:
Done. The (unit & integration: psql, rmq…) tests of a real-world project are now 100% green with Rust. ![]()
News #11:
Added to the concurrent/parallel benchmark.
There is the same factor of 2 between Rust and Go, and overall, Rust is about 20 times faster than JavaScript.
News #12:
And there you have it: Rust has finally caught up with C++: under the 10 ms barrier!
… or so I thought.
It turns out that was a phantom goal. Fatigue and all those late nights grinding on these backends led me to make a pretty crazy mistake with the units of measurement. In reality, the pscpp (C++) metrics are actually closer to a full second, making it about a factor of “only” 2x faster than Go (psgo). Given the fact that both psgo and pscpp come from the same work (purescript-native), this actually makes a lot more sense and is much more consistent with my empirical observations so far, which also show roughly a factor of 2 difference between Rust (purust) and Go (gopurs). (This also aligns with the initial intuition that TASTs are of great value because they provide all the necessary type information to AOT backends: pscpp is based on untyped ASTs.)
In short, my unit mistake at least motivated me to push hard. The good news is that it leaves us with a very positive takeaway for purust: it’s incredibly cool to have such a high-performance low-level backend. 100x faster than pscpp ![]()
That being said, I’m going to take a break for a few days to catch up on some much-needed sleep and recharge my batteries.
CheerzZz… ![]()
News #13:
Just out of curiosity, I added Koka to the benchmark suite to see where our recent advancements stand against a language now famous for its raw functional performance (thanks to its FBIP and Perceus architecture).
The results are very positive: purust is 3x faster. Koka achieves a better score than pscm (Scheme), which is impressive for pure functional code. It really puts into perspective how effective the AOT/TAST approach is when translating high-level semantics down to flat imperative structures.
Eventually, I’ll add more stress tests to confirm this initial concrete feedback on the performance comparison with Koka.
I wrote the native implementation with the help of an AI, as I am not at all familiar with the language (though I find it fascinating, but that’s another story). If anyone here knows Koka, feel free to review the benchmark script to check if it’s idiomatic or if it can be improved. You can find the code here.
News #14:
Added Haskell, OCaml and C to the benchmark. The reference is now ~ 8.7ms, and purust has (almost) reached it. (Microsecond-level optimizations still need to be done.)
New stress tests are coming (n-queens, breadth-first search…)
News #15:
Last, but not least.
Fable has been added to the benchmark: purust is 10x faster. (Further evidence that the major phase of optimizations is likely behind me.)
(For those who can’t zoom in: purust is < 10 ms, while Fable takes more than 100 ms.)
News #16:
A few adjustments are underway, but all tests for approximately 54 modules are now passing (purust-*). Next step: the official tests.
Very interesting project! Testing it out to speed up a mostly pure code project (~50K LOC PureScript) that I’m running on NodeJS. I was actually able to compile most of the project and even run some unit tests. Not enough to get a sense of the performance comparison but it feels like it’s close ![]()
Cut some tickets to the repo with the findings. 2 I was able to work around. Another one not (the freeap one). Hopefully this is helpful!
Thank you George @gwwatkins
![]()
I didn’t think this would work on projects right away. Exciting news! Maybe we’re closer to seeing the light at the end of the tunnel than I thought.
Thank you so much for your support and your issues; I’ll take a close look at them. Even though gopurs is my priority right now, purust is the project that seems most interesting to me for PureScript in the long run, so I’m taking all of this very seriously.
Edit: Fixed all issues. I’ll probably give you a complete feedback on github by the end of the day (right now on a train).
Thank you Kevin for the super fast fixes and replies!
Looks like the input was met positively
I can continue give a bits of feedback as I work on this on the side ![]()
I could try the go back end as well, though I liked the idea of porting some of the tightest loops to Rust. Since one of the optimizations that worked for this project was some some manipulating the data layout using JavaScript arrays.
Absolutely, yes: I’m very happy to see people giving it a try, and that will help me a lot. It’s quite a large project, and every piece of feedback will be a great help to me. I’ll eagerly welcome all your feedback. Feel free to run your tests. Whenever you feel like it, I won’t mind at all (quite the opposite).
I’m going to focus my immediate efforts on the Array Processing test for Rust (+ Array Indexing, recently added). I’ll let you know when it’s fully optimized and ready to go, so you can test it ![]()
I took advantage of a bout of unwanted insomnia to improve the performance of the Array Processing test, which is now 100x faster: 25 μs → 0.25 μs (vectorization, fusion…). I’m actually still working on improving it, to get even closer to imperative C. ![]()
But I think you can already start testing things on your side, since it’s now much better than JS. I hope my optimizations address your own bottlenecks. (If you notice anything running slowly on Arrays, please don’t hesitate to let me know so I can add some tests, for example.)
purust branch edge (2b15ad6)
purust-arrays branch master (23600e8)
purust-foldable-traversable branch master (00be4d3)
purescript-backend-optimizer(-purust) branch edge-purust (3fd2eea)
0.25 μs → 0.0366 µs. Now better than “hand-written” imperative C, in the benchmark. ![]()
You can find more here: Perf improvements on Arrays (WIP) · Issue #4 · 0x000000000000000000001/purust · GitHub