21 ms·
Ruby YJIT Ported to Rust
- jfmc 5y ago"YJIT code ported from C99 to Rust" Beyond passing the test suite, are there more numbers to compare both versions? (e.g., compilation time, lines of code, size of binaries, performance, etc.)
- tmikaeld 5y agoWas looking for the same thing, what does this mean for Ruby performance?
- deleted 5y ago[deleted]
- block_dagger 5y agoNothing
- ModernMech 5y agoAccording to the post not much. The Rust version performs about the same because it generates mostly the same machine code.
- Rafert 5y agoYJIT benchmarks can be found at https://speed.yjit.org/ https://speed.yjit.org/ The Rust port doesn't change performance much according to the pull request description.
- npalli 5y agoYour own link states -- Overall YJIT is 33.4% faster than interpreted CRuby! On Railsbench specifically, YJIT is 32.4% faster than CRuby!
- WJW 5y agoYes, but YJIT in rust is the same ~33.4% faster than vanilla CRuby than YJIT in C. The rewrite into Rust is expected to make YJIT easier to maintain and that may in turn make possible further improvements to code generation, but the rewrite generates the same machine code (and therefore the same speedup) as before.
- ewalk153 5y agoI didn't know this was public, sweet! Nice that the tooling that generates this report is also published: https://github.com/Shopify/yjit-metrics https://github.com/Shopify/yjit-metrics
- rvz 5y agoIt means completely nothing for performance.
- pizza234 5y agoVery likely, the performance of a JIT comes from: - the architecture of the JIT itself - the generated code AFAIK, the Rust YJIT doesn't change any (they explicitly say that the generated code is approximately the same), so there no significant difference in performance should be expected.
- asymmetric 5y agoThe PR itself says: > The new Rust version of YJIT has reached parity with the C version, in that it passes all the CRuby tests, is able to run all of the YJIT benchmarks, and performs similarly to the C version (because it works the same way and largely generates the same machine code). We've even incorporated some design improvements, such as a more fine-grained constant invalidation mechanism which we expect will make a big difference in Ruby on Rails applications.
- faitswulff 5y agoRoR comparison benchmarks would be nice to see.
- matsadler 5y agoI think the goal of this right now is just to match the C version. The C implementation of YJIT supported x86 Unix/Linux platforms, and it sounds like adding Windows and arm64 support, plus other improvements was a daunting task with the tools C provides. Now it’s in Rust we’ll hopefully see further improvements quicker.
- anitil 5y agoThis is the first time I've felt that Rust is starting to eat C's lunch.
- rubyfan 5y agoCan you say more about why you think that?
- anitil 5y agoI started in C and generally when people say 'rewrite it in Rust' I just roll my eyes, because I know how hard that is. But seeing it happen on a sophisticated project has made me take another look. Obviously for the embedded world everything is pitched at C currently and I don't think that will change, but for larger projects this is proof that my intuition was wrong. I suppose that's a long winded way of saying that it might be time for me to learn Rust.
- tormeh 5y agoRust will eclipse C++. C is a harder nut to crack, particularly for the embedded space where ease of implementing and maintaining a compiler back-end/code-emitter for your new weird 8-bit architecture is important. C is pretty close to an assembly macro and it's barely updated, which is great for that use-case. But for use cases like interpreters Rust is perfectly suitable.
- vlovich123 5y agoThis position is like saying C or C++ won't eat ASM's lunch. While technically true since there's a lot of ASM code still being written, especially for extremely low-level or high performance code, the vast majority of C and C++ developers don't actually touch ASM (i.e. C/C++ dominate ASM in terms of number of developer hours spent). I think you may also be overlooking the GCC backend for rustc and gccrs, a ground-up standalone reimplementation of the Rust language frontend for GCC. Both of those should drastically improve the coverage and availability of Rust to all the same platforms you would be using GCC to compile C code for. Depending on the compiler support, you might get that architecture for free unless the vendor is providing their own C compiler. The harder part is that your new weird 8-bit architecture probably won't benefit as much from the strong nostd ecosystem of libraries, so the overhead of writing Rust won't be counterbalanced. Still, like I said at the outset, this is an extremely niche use-case. Rust doesn't have to wipe C or C++ from the map for it to crack that nut. The harder nut for Rust to crack I think is actually C++. There are extremely large C++ codebases. Industry would love for there to be a significantly easier/cheaper story to tell in terms of integrating Rust with those codebases. That way you could set metrics around converting the codebase, new code has to be written in Rust etc. However, the challenge is that Rust can only replace components with very well-defined boundaries. Those boundaries are less clearly defined in C++ codebases than they are in C codebases (linkage + templates in particular are challenging). To truly crack the C++ nut probably requires solving this problem unless Rust codebases just starting eating C++ codebases commercially through development velocity (which is a much longer and harder path).
- WolfOliver 5y agoWhat is the benefit? Can I run Ruby in the browser now?
- WJW 5y agoYes you can run Ruby in the browser if you want, but not because of this PR. Ruby-in-WASM was merged a few weeks ago. This PR rewrites the YJIT just-in-time compiler code from C into Rust, because the dev team likes Rust better and expects that it will make development of new features easier.
- vinceguidry 5y agoDon't forget Opal! https://opalrb.com/ https://opalrb.com/
- erk__ 5y agoThe proposal for this was previously discussed at: https://news.ycombinator.com/item?id=29971360 https://news.ycombinator.com/item?id=29971360
- throwaway-m3232 5y agoWhy not C++, for better portability? If I want to design my own CPU, I will have to add it to GCC. But Rust is LLVM so if I want to support Ruby-jit on my CPU, I will also will have to support LLVM.
- sanxiyn 5y agoThis is a non-issue. YJIT only targets x86-64. After all, this is a JIT. If you designed a new architecture X, you need to port YJIT itself to target X, in addition to GCC, LLVM, etc.
- throwaway-m3232 5y agoOh, so YJIT is highly coupled to x86-64? Porting GCC + yjit is less work than porting GCC + yjit + LLVM.
- FooBarWidget 5y agoIt's not like new architectures appear very quickly, much less adopted very quickly. The benefits of maintenance overhead reduction and development speed increase, far outweight the theoretical downside of having to port LLVM to that new architecture.
- byroot 5y agoIt’s not that it’s highly coupled, just that it’s still the early days and only x86_64 was on the roadmap. Arm64 is planned, and will hopefully make it into Ruby 3.2
- FullyFunctional 5y agoAnd with an Arm64 backend, adding RISC-V is probably going to be a walk in the park.
- lalaithion 5y agoWhy even port GCC at all, and not simply LLVM?
- xutopia 5y agoHow will this benefit Ruby?
- kibwen 5y agoMotivation: https://bugs.ruby-lang.org/issues/18481 https://bugs.ruby-lang.org/issues/18481 "The motivation behind this is that we are facing challenges in terms of code maintainability. As you know, JIT compilers can get very complex, and C99 doesn't offer many tools to manage this complexity. There are no classes and methods, limited type checking, and it's hard to fully separate code into modules, for instance." "We believe that having access to object oriented programming and a more expressive type system would help us manage growing complexity better and also improve the safety/robustness of YJIT. For instance we would like to add Windows support and a new backend to YJIT. That means we’ll have two separate backends (x86, arm64) and we’ll need to support two different calling conventions (Microsoft, SystemV), but currently, we have limited tools to build the abstractions needed, such as preprocessor macros and if-statements."
- czbond 5y agoThank you for posting the motivation - I was curious the "why"... and maintainability now explains it.
- deleted 5y ago[deleted]
- Linda703 5y ago[flagged]
- The_rationalist 5y ago
- epage 5y agoI found this part odd > . If YJIT is built in dev mode, then cargo is used to fetch development dependencies, but when building in release, cargo is not required, only rustc I'm not finding any information on why they bypass cargo and build directly with rustc. I'm curious what requirements led to this.
- rtpg 5y agoMaybe the production release has no dependencies to download, but the dev release has some helper stuff for running tests etc?
- nightpool 5y agoMy guess is that this is a tradeoff made to make it more compatible with downstream distro packaging systems like Debian and Redhat, who generally look very negatively on requirements to use external package managers like Cargo. By keeping their set of dependencies very small, removing Cargo from their build process has tons of benefits in terms of how complex it will be to compile the Ruby codebase
- steveklabnik 5y agoBoth Debian and Red Hat package Cargo, and also package various Rust crates as their own native packages, and then have Rust programs use Cargo to use them. (Okay actually I’m unsure about Red Hat, but this is how Fedora does it…)
- the_duke 5y agoThe Cargo.toml file gives the answer: https://github.com/Shopify/ruby/blob/rust-yjit-upstreaming/yjit/Cargo.toml#L21 https://github.com/Shopify/ruby/blob/rust-yjit-upstreaming/y... There is only a single, optional dependency which is apparently only used for testing.
- stormbrew 5y agoCargo is .. not a pleasant build tool to integrate into other build systems. If you have a project (like mainline ruby) where the dominant mode is C and you need to integrate some rust into it, you will eventually feel like it'd be a useful use of your time to bypass cargo and use the compiler directly. Cargo is a fantastic tool, easily one of the best of its ilk, but real talk: it needs to be normalized that sometimes you don't want or need to use it. It is fit to a very specific set of tasks (mostly producing stand-alone binaries), and that set of tasks is a subset of the tasks rust as a whole is fit for.
- dj_gitmo 5y ago> ... it works the same way and largely generates the same machine code How can they make this determination? Do they just eyeball a few sections of the machine code from each output? Is there some tool that can compare binaries? Is this just a very literal, function by function, translation from C to Rust? I don't know much reading/comparing machine code.
- pjmlp 5y agoThey mean the output of JIT compiler, not the binary itself.
- pizza234 5y agoI'm not familiar with what YJIT generates, however, in general terms, if the ASM code for a given bytecode is small enough (Which I think it is), one can just compare them side by side, or just log them and compare them separately. I think a JIT for Ruby should compile relatively small chunks of ASM, not big walls of code (but again, this is my guess).
- MuffinFlavored 5y agoI wonder if they found any bugs in the C99 version due to Rust's "memory/type safety" and all that?
- fuzzythinker 5y agoHere's a benchmark [1] done in Jan'22 against many ruby implementations, truffleRuby [2] seems to be way ahead in most, and at least ahead in all. Why truffleRuby isn't talk about much here? [1] https://eregon.me/blog/2022/01/06/benchmarking-cruby-mjit-yjit-jruby-truffleruby.html https://eregon.me/blog/2022/01/06/benchmarking-cruby-mjit-yj... [2] https://github.com/oracle/truffleruby https://github.com/oracle/truffleruby
- pizza234 5y agoWhen I read about its performance, I had the same thoughts, however, I was surprised to read this in the Github project readme: > TruffleRuby might not be fast yet on Rails applications and large programs. Notably, large programs currently take a long time to warmup on TruffleRuby and this is something the TruffleRuby team is currently working on. Large programs often involve more performance-critical code so there is a higher chance of hitting an area of TruffleRuby which has not been optimized yet. I guess that they have a high-performing JIT, that is optimized for small but not large programs yet. I'm curious though, what, technically, makes such difference.
- stormbrew 5y agoThis is always a problem for any JIT. Large codebases, especially ones as heavy on dynamic code paths as rails, run individual pieces of code less frequently than smaller ones (because they're just doing more work in general, and in rails' case are constantly spawning new code to deal with). Then you have to instrument the code while it's running under a VM to decide what (and how) to JIT, and then you have to compile and assemble it. You also probably have to deal with some quasi-locking around the call sites as you switch code from using the VM to using the JIT. So, basically by the laws of thermodynamics, all else equal a JITing VM will be slower than a non-JITing one, and the benefits of JIT won't kick in until you have enough code instrumented and compiled to make a dent in that performance loss from the extra work. And then, the cleverer your JIT, and the more you optimize the code under compile, the more off-balance this gets, because doing those things gets more expensive.
- petercooper 5y ago
- hardwaregeek 5y agoThis is so cool! If new contributions to Ruby could be written in Rust, I'd be a lot more inclined to contribute. I don't think I'm alone here. Andy Kelley noted that the new Zig compiler has significantly more contributors, likely due to it being written in Zig and not C++. Some people may roll their eyes at this, but it is a lot more enticing to work on a Rust codebase than a C/C++ one. I'm less likely to screw up and create a serious bug; I get a lot more help from the compiler; the build system is standardized and simple; and it's just plain fun.
- faitswulff 5y agoUnfortunately: > To be clear, it's OK to use Rust to implement YJIT (and other optional features in the future), but mainline CRuby will not be implemented in Rust. - Matz, https://bugs.ruby-lang.org/issues/18481#note-14 https://bugs.ruby-lang.org/issues/18481#note-14 On the other hand, there is Artichoke Ruby: https://github.com/artichoke/artichoke https://github.com/artichoke/artichoke
- hardwaregeek 5y agoTrue, although Matz has changed his mind in the past (type annotations come to mind). I wouldn't be surprised if people notice that YJIT contributions are far more common, Matz may reconsider this.