7 ms·
"write as much Ruby as possible, especially because YJIT can optimize Ruby code but not C code" I feel like I'm not getting something. Isn't ruby a pretty slow
by internetter 2y ago
"write as much Ruby as possible, especially because YJIT can optimize Ruby code but not C code"
I feel like I'm not getting something. Isn't ruby a pretty slow language? If I was dipping into native I'd want to do as much in native as possible.
- kevingadd 2y agoWhen dealing with a managed language that has a JIT or AOT compiler it's often ideal to write lots of stuff in the managed language, because that enables inlining and other optimizations that aren't possible when calling into C. This is sometimes referred to as "self-hosting", and browsers do it a lot by moving things into privileged JavaScript that might normally have been written in C/C++. Surprisingly large amounts of the standard library end up being not written in native code.
- internetter 2y agoOh, I am indeed surprised! I guess I always assumed that most of the JavaScript standard library was written in C++
- achierius 2y agoWell, most all of the compiler, runtime, allocator, garbage collector, object model, etc, are indeed written in C++ And so are many special operations (eg crypto functions, array sorts, walking the stack) But specifically with regards to library functions, like the other commentator said, losing out on in lining sucks, and crossing between JS and Native code can be pretty expensive, so even with things like sorting an array it can be better to do it in js to avoid the overhead... Eg esp in cases where you can provide a callback as your comparator, which is js, and thus you have to cross back into js for every element So it's a balancing game, and the various engines have gone back and forth on which functions are implemented in which language over time
- jitl 2y agoMuch of the standard library in v8 is written in Torque, a custom language. https://v8.dev/docs/torque https://v8.dev/docs/torque Example file for array.find(…): https://github.com/v8/v8/blob/5fe0aa3bc79c0a9d3ad546b79211f07105f09585/src/builtins/array-find.tq#L120 https://github.com/v8/v8/blob/5fe0aa3bc79c0a9d3ad546b79211f0...
- kenhwang 2y agoRuby has realized this as well. When running in YJIT mode, some standard library methods switch to using a pure ruby implementation instead of the C implementation because the YJIT-optimized-ruby is better performing.
- pjmlp 2y agoThat is where a JIT enters the picture, ideally a JIT can re-optimize to an ideal state. While this is suboptimal when doing one shot execution, when an application is long lived, mostly desktop or server workloads, this work pays off versus the overall application. For example, Dalvik had a pretty lame JIT, thus it was faster calling into C for math functions, eventually with ART this was no longer needed, JIT could outperform the cost of calling into C. https://developer.android.com/reference/android/util/FloatMath https://developer.android.com/reference/android/util/FloatMa...
- genewitch 2y agoDepending on the math (this is a hedge) you need, FORTRAN is probably faster still. Every time I fathom a test and compare python, fortran, and C, Fortran always wins by a margin. Fortran:C:Python 1:1.2:1.9 or so. I don't count startup I only time time to return from function call. Most recently I did hand-looped matrix math and this ratio bore out. I used gfortran, gcc, and python3.
- pjmlp 2y agoSure, but that doesn't fit the desktop or server workloads I mentioned, I guess we need to except stuff like HPC out of those server workloads. I would also add that modern Fortran looks quite sweet, the punched card FORTRAN is long gone, and folks should spend more time learning it instead of reaching out to Python.
- doppp 2y agoIt's been fast for a while now.
- Thaxll 2y agoEven a 50% or 2x speed improvment still make it a pretty slow language. It's in the Python range.
- CyberDildonics 2y agoWhat is fast here? Ruby has usually been about 1/150th the speed of C.
- kenhwang 2y agoIf the code JITs well, Ruby performs somewhere between Go and NodeJS. Without the JIT, it's similar to Lua.
- CyberDildonics 2y agoIf the code JITs well What does this mean? Any JIT can make a tight loop of math and arrays run well but that doesn't mean a typical program runs well.
- kenhwang 2y agoFor Ruby, it's code where variables and method input/return types can be inferred to remain static, and variable scope/lifetime is finite. From my understanding, much of the performance gain was from removing the need for a lot of type checking and dynamic lookup/dispatch when types were unknown. So basically, writing code similarly to a statically typed compiled language.
- neonsunset 2y agoNode uses V8 which has a very advanced JIT compiler for the hot code, which does a lot of optimizations for reducing the impact of JS's highly dynamic type system. The claim that Ruby YJIT beats this is not supported by the data to put it mildly: https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/node-ruby.html https://benchmarksgame-team.pages.debian.net/benchmarksgame/... (scroll down on each submission and you will see it uses YJIT) (and Go is not a paragon of absolute performance either)
- neonsunset 2y agoFFI presents an opaque, unoptimizable boundary of code. Having chatty code like this is going to cost a lot. To the point where this is even a factor in much faster languages with zero-cost-ish interop like C# - you still have to make a call, sometimes paying the cost of modifying state flags for VM (GC transition). If Ruby YJIT is starting to become a measurable factor (after all, it was slower than other, purely interpreted, languages until recently), then the same rule as above will become more relevant.
- hahahacorn 2y agoThere's a phenomenal breakdown by JPCamara (https://jpcamara.com/2024/12/01/speeding-up-ruby.html https://jpcamara.com/2024/12/01/speeding-up-ruby.html) on why the Ruby#each method was rewritten in Ruby (https://bugs.ruby-lang.org/issues/20182 https://bugs.ruby-lang.org/issues/20182). And bonus content from tender love: https://railsatscale.com/2023-08-29-ruby-outperforms-c/ https://railsatscale.com/2023-08-29-ruby-outperforms-c/. TL;dr - JIT rules.
- hinkley 2y agoThere was a little drama that played out as Java was getting a proper JIT. In one major release, there was a bunch of Java code responsible for handling some UI element activities. It was found to be a bottleneck, and rewritten in C code for the next major release. Then the JIT became properly useful, and the FFI overhead was more than the difference between the hand-tuned C code and what the JIT would spit out on its own. So in the next major release, they rolled back to the all-Java implementation. Java had a fairly reasonably fast FFI for that generation of programming language, but they swapped for a better one a few releases after that. And by then I wasn't doing a lot of Java UI code so I had stopped paying attention. But around the same time they were also making a cleaner interface between the platform-specific and the general Java code for UI, so I'm not entirely sure how that played out. But that's exactly the sort of see-sawing you need to at least keep an eye out for when doing this sort of work. Would you be better off waiting a couple milestones and saving yourself a bunch of hand-tuning work, or do you need it right now for political or technical reasons?
- kazinator 2y agoIf FFI calls are slow (even slower than Ruby -> Ruby calls) then informs the way you use native code. You look for workflows whereby frequent calls to a FFI function are avoided: e.g. large number of calls in some inner loop. Suppose such a situation cannot be avoided. Then you may have no recourse than to move that loop out of Ruby into C: create a custom FFI for that use case which you can call once and have it execute the loop, calling many times the function you really wanted to call. If the FFI call can be made faster, maybe you can keep the loop in Ruby. Of course that is attractive to people writing an application in Ruby. That's how I interpret keeping as much code Ruby as possible. Nobody in their right mind wants to add additional application-specific jigs written in C just to use some C piece. Once you start doing that, why even have FFI; you can just create a module. One attractive point about FFI is that you can take some C library and use it in a higher level language without writing a line of C.