OP here: I think you're reading too much into the title. It's not about the failure of Rust. It's about where I stepped in with some custom optimizations for better performance. If you read the blog post, the solution implemented is very Rust-y as well. It uses a newtype with custom methods to try and make the code as nice and readable as possible.
FWIW this post was very well received on the Rust subreddit. They loved it and it got over 350 upvotes, so that community definitely didn't receive it as some sort of attack on Rust.
I don't think it's fair to write a misleading title then tell people "they're reading too much into it".
Implying one thing then walking it back in the article or having the article be about something totally different, then saying people should read the article and not pay attention to the title is just manipulative to your audience.
The problem is that there isn't anything misleading about the title. It is well understood that creative packing of data can provide optimizations under certain circumstances. Nobody should have reason to think otherwise. The title quite accurately captures what the rest of the article is about as well as any title possible can.
What appears to be happening as we see in several comments is that some users cannot find any technical reason to use Rust so they rely on a belief that it is somehow magically perfect to justify using it and and the idea that it hasn't perfectly found some creative packing solution, despite the rest of us wondering why one would expect any compiler to – it not really being its job, is felt as an attack on their use of Rust. Someone developing irrational feelings towards an inanimate tool isn't on the article's author.
What's misleading about the title is that the title implies something about rust, while the content does not.
Like I said in the first place, you can remove the word rust, and nothing changes. That's how you know what's wrong.
It's like a news report saying "black man caught embezzeling". It might be a fact, but it's an irrelevant fact, and it begs the question why it was pointed out. He was probably also a vegetarian, Jewish, a bird watcher, an uncle...
And it's not that there is some weird rule that you have to avoid saying black or rust or whatever. It's simply that if you say something, then the _only_ reasonable way to interpret it is that there was some reason to say it.
You state an equation or give a list of items, it is irrational to assume anything other than that all of the terms or items are relevant.
In this case, rust is just the language being used, which is happenstance. It doesn't matter what language was used. You don't have to go out of your way to hide the language or any silly suggestion like that, but reading the title alone says that there is something about rust and enums. There only 3 items in the title, rust, enum, 64bit word. You can't fault anyone for defaulting to the conclusion that rust, enum, and 64bit word are the essential concepts that will be discussed.
The article isn't bad, and frankly the title isn't even so bad as to be a moral failing or anything. They ARE happening to be working in rust while developing this optimization.
It's simply that it's also entirely correct and reasonable to read the title as saying the words that it says. And the title says something that the content does not.
Right, Rust tells us something important: How the data was packed pre-optimization. This is useful information as, at least those with some familiarity with Rust, will have an understanding of what is being replaced.
You wouldn't be able to reasonably use something like "Replacing an Enum with ..." because, especially where enum in Rust means what other languages call sum types, the data representation can be anything. But even the more traditional use of enum isn't defined by any particular data representation. The whole point of an enum is that any value used in implementation is treated as being opaque! Whereas in this case the value is significant.
I mean, you wouldn't be able to no more than you could replace the title with "Hey you, yes you, read this". Which obviously you could do. But it would be a poor title as you wouldn't be able to figure out what the article is about. This title is great because you can predict exactly what the article is about before reading it. I'd even go as far as to say that this is one of the better titles I've seen on HN in a long time.
Granted, it does require technical familiarity to be able to grok it. I can appreciate those who have developed irrational feelings for an inanimate tool aren't coming with a very strong technical background, but who cares about them? The intended audience is clearly technical folk.
I have no idea what you are trying to comment on. Nothing I said.
Changing the title to "hey you" is a ridiculous meaningless idea that does not relate in any way to "you can remove the word rust and nothing changes". I can only assume you simply don't know how to read, and so there can be no possibility of communication. It was not an obscure indecipherable construction, and your inability to understand it is yours alone.
You fabricate this idea that I have some feeling about rust, and then base a bunch of weird arguments on that invented idea. I neither like nor dislike rust. It's a piece of tech that seems to be functional enough for some tasks. The entire point was that it has no bearing at all, positive or negative. But that is somehow defending a sacred cow?
> Changing the title to "hey you" is a ridiculous meaningless idea that does not relate in any way to "you can remove the word rust and nothing changes".
It totally relates. If you remove 'Rust' then you cannot decipher the title. Rust has a known packing scheme when using enums, which is significant when replacing that packing scheme with a creative alternative. 'Enum' alone does not. Again, the whole idea behind an enum construct is to make any implementation values opaque! Any values used in a particular implementation are implementation dependent. As explained before, if you keep the implementation you are talking about a secret then the words become no more useful than "hey you...". The starting point is central to the story about a performance optimization being gained. One must be able to understand what the starting point is in order to extract anything useful from learning about the destination.
> You fabricate this idea that I have some feeling about rust
Whatever do you mean? The bit about feelings was clearly in reference to the earlier comment that spoke to even earlier comments that had nothing to do with you. It's a big world out there. What makes you so sure it revolves around you?
Author here. The disassembly for the old enum handling had many spills, simply because the old value enum can't fit in a single register. If you have an instruction that two operands with two of those big value enums, it needs 4 registers instead of 2. That, coupled with better cache-friendliness, explains a lot.
Absolutely, I agree. I suspect that explicit branch for the hot path is doing a lot too.
Separating the hot path into a prefix before calling into a separate cold function should still generate better code. Your prefix only needs to allocate registers and stack space for just that single path. You would only pay the spilling costs in the old code off the hot path rather than every instruction. And I would expect the branch prediction accuracy of that prefix check to be higher than having the hot and cold paths all dispatching through the same tree of branches.
However it's speculation until you measure so I could be wrong.
Good article in any case, I enjoyed reading along.
100% agreed (see my sibling comment), this all accumulates for in-language function calls,etc since code at runtime often spends a surprising amount of time just moving around values instead of doing useful work, having them just as singular register values really helps a ton.
I'm assuming you mean that this tech became available in OpenCV 25 years ago, but as it turns out, the underlying tech can be traced back much further, at least as far as 1977! :)
https://ieeexplore.ieee.org/document/1674847
G. J. Vanderbrug and A. Rosenfeld, “Two-Stage Template Matching,” IEEE Transactions on Computers, Vol. C-26, No. 4, pp. 384–393, April 1977.
DOI: 10.1109/TC.1977.1674847
But also generally, I was looking at other web-based drum machines, and most of them are either super basic, full of ads, or they have bad cryptic UIs. I also wanted to design a more advanced sequencer with a timeline that would have an intuitive UI to work with.
I built a sequencer in NoiseCraft, a browser-based music programming language I built a few years ago (e.g. https://noisecraft.app/101), but you can't chain pattern in this sequencer, which makes it harder to create longer piece (though people have found workarounds).
It's easy to dismiss our efforts, but Ruby is just as dynamic if not more than Python. It's also a very difficult language to optimize. I think we could have done the same for Python. In fact the Python JIT people reached out to me when they were starting this project. They probably felt encouraged seeing our success. However they decided to ignore my advice and go with their own unproven approach.
This is probably going to be an unpopular take but building a good JIT compiler is hard and leadership matters. I started the YJIT project with 10+ years of JIT compiler experience and a team of skilled engineers, whereas AFAIK the Python JIT project was lead by a student. It was an uphill battle getting YJIT to work well at first. We needed grit and I pushed for a very data-driven approach so we could learn from our early failures and make informed decisions. Make of that what you will.
Yes Python is hard to optimize. I Still believe that a good JIT for CPython is very possible but it needs to be done right. Hire me if you want that done :)
> whereas AFAIK the Python JIT project was lead by a student.
I am definitely not leading the team! I am frankly unqualified to do so lol. The team is mostly led by Mark Shannon, who has 10+ years of compiler/static analysis experience as well. The only thing I initially led was the optimizer implementation for the JIT. The overall design to choose tracing, to use copy and patch, etc. were other people.
> However they decided to ignore my advice and go with their own unproven approach.
Your advice was very much appreciated and I definitely didn't ignore your advice. I just don't have much say over the initial architectural choices we make. We're slowly changing the JIT based on data, but it is an uphill battle like you said. If you're interested, it's slowly becoming more like lazy basic block versioning https://github.com/python/cpython/issues/128939
You did great work on YJIT, and I am quite thankful for that.
Thanks for the response Maxime, your work on YJIT is astounding. The speedup from YJIT was a huge improvement over cRuby or MJIT, and the work was done relatively quickly compared to Python which seems to always be talking about this JIT but we are never seeing a comparable release.
Having had no experience in JIT development but having followed the faster cpython JIT progress on a weekly basis, I do find their JIT strategy a bit weird. The entire decision seemed to revolve around not wanting to embebed an external JIT/compiler with all that entails...
At first I thought their solution was really elegant. I have an appreciation for their approach, and I could have been captivated myself to choose it. But at this point I think this is a sunk cost fallacy. The JIT is not close to providing significant improvements and no one in the faster cpython community seems to be able to call the shot that the foundational approach may not be able to give optimal results.
I either hope to be wrong or hope that faster cpython managment has a better vision for the JIT than I do.
YJIT is optimized primarily for web workloads. We look at rails performance a lot, but also at various other libraries that are used in that context. If you look at the headline benchmarks at https://speed.yjit.org, it will give you an idea of what we're mostly focused on. This is in contrast with academic compiler project, which often focus on microbenchmarks and code that is very different from the code users actually run in practice.
YJIT or TruffleRuby: I'm biased being that I work on YJIT. The nice thing about YJIT is that it's likely to work out of the box, and just be a matter of calling `ruby --yjit` to turn it on. It will probably use a lot less memory than TR, and it's probably more likely to deliver the result you're looking for at this time (speed boost, no hassle).
That being said, for some small or specialized applications, TruffleRuby could deliver much higher peak performance. If you don't restart your server often and you have a lot of memory available, then maybe you don't care about warm-up time or memory usage, and TruffleRuby could be the right tool for you. Feel free to run your own benchmarks and also to blog about the results (though if you do, please share as much details about your setup as possible).
Yes, Marc Feeley was my PhD advisor. We came up with the original idea together. I also see it as a development of the work I did in my M.Sc. thesis on type-driven versioning of functions. Basic block versioning is lazy, type-driven tail splitting of code.
FWIW this post was very well received on the Rust subreddit. They loved it and it got over 350 upvotes, so that community definitely didn't receive it as some sort of attack on Rust.
reply