Rust Faster
llogiq.github.io
llogiq.github.io
1. The benchmarks game is mostly a game of who can solve the problem fastest with the constraint of "all the code has to be in this language." It's not about how anyone would realistically write the code; if ludicrous optimizations were in-scope for any real-world project, so would be calling out to a different language. It's worse than the usual problem of benchmarks being unrepresentative of real code; the implementations are also unrepresentative.
2. Apparently performant Haskell involves unchecked raw memory access? What's the story there?
They tend to tell you as much or more about the cleverness/knowledge/available free time of the people writing the specific implementation in each language as they tell you about the languages’ inherent differences.
I don’t think it’s a solvable problem though, as there’s no perfect definition of “how anyone would realistically write the code”. Realistically, people are going to write the first naïve implementation they can think of until it becomes a performance problem and someone has time/resources to throw at speeding things up. In the case that a piece of code is a bottleneck and performance matters enough to devote engineering effort, folks will start doing all kinds of crazy “unrealistic” optimizations to real-world code.
I realize that this would not necessarily make the code any more realistic or idiomatic. On the contrary, it could make the code extremely contrived for some algorithms in some languages. Some combinations might even be unimplementable.
But I don't care about that, because, as you say, what is and isn't idiomatic is very subjective and it gets thrown out anyway once we decide that some piece of code does need to run fast.
What makes these benchmarks pretty useless is that you don't know whether the choice of algorithm or the choice of programming language dominates a particular result.
You can do that comparison and publish the results.
>> choice of algorithm or the choice of programming language<<
Do the n-body programs implement different algorithms?
http://benchmarksgame.alioth.debian.org/u64q/performance.php...
"We are trying to show the performance of various programming language implementations - so we ask that contributed programs not only give the correct result, but also use the same algorithm to calculate that result."
Thanks for the correction.
Also, because of the differences between such a wide range of programming languages, there has to be some slop and flexibility in the way the programs are allowed to be written -- otherwise it really would be C written in Haskell.
http://benchmarksgame.alioth.debian.org/dont-jump-to-conclus...
It would be interesting if entries were categorized into idiomatic and non-idiomatic representations of that language, but that would also require people agree on what is idiomatic for that language, which is easier said than done in a lot of cases.
If only you'd look at the code.
There can be several quite different programs for the same language implementation:
http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...
No that is not a usual constraint, many implementations use third party libraries. E.g., regexdna implementations usually rely on some regex library and pidigits just measures libgmp.
Go aims to be simple with the aim of being 'easy' to start writing idiomatically within a few days of jumping into the language. Comparatively, rust is a behemoth in terms of complexity.
There's the completely relevant compilation speed difference: if rust could compile within 5-10x the time go does, it would be much more pleasant to work with. Being able to compile within 2 seconds on large projects is crazy for iteration speed; having to wait upwards of 10 seconds on toy projects is not.
However, rust is stupid fast while also being safer than go. Also, generics; that's a flamewar for another day.
Context: I've been working with go for around 2-3 years now. I recently decided to pick up rust because of the guarantees it provides along with the crazy performance.
We don't really do any optimizations on the Rust side and just hand over IR to LLVM. This IR isn't of the type LLVM was built to deal with (pervasive noalias, lots of iterators, etc). It can optimize it, just that it's slow. We can work on giving better IR there.
So type check is slow, but it isn't the reason we're slow. (Still, improvements to type check will help)
As someone who's been around Rust for a long time but writes very little code in the language, I'm looking towards the MIR work and language services effort to improve this. The language is reasonable to work with once you're over the learning curve and you can mentally visualize the allocations/pointers/borrows moving around but the learning curve is really hard. Having a faster feedback loop on a higher information density interface than console text (I have a dream of dynamic borrow/lifetime overlays) to act as an extended tutorial would go a very long way.
There is one pass that is certainly "more tricky" from an algorithms perspective, but will result in the rules being more intuitive from a user's perspective.
This is really what needs to happen for wide Rust uptake. If you look at IRC most people starting with Rust immediately run into compile problems that they don't know how to solve.
I did and I write C++11 with rval references all day every day.
I'd bet that if they fixed up type inference to work everywhere (like Haskell or even like an ML) that'd reduce the perceived complexity as beginners wouldn't need to figure out type annotations by hand all the time.
It might not be such a big-deal in Rust. I don't have enough experience with it. But if it ever gets HKTs, it wouldn't surprise me if their interaction with typeclasses becomes a pain-point without (nearly) global type inference.
I write some in F# and I never specify types unless there's an obvious clarity issue or a type inference limitation. Most of the time that's because type inference in F# flows only one way and the whole .NET instance methods don't offer alternative syntax (i.e., you must write x.Foo, and you can't do that without knowing x's type - it won't get inferred).
When I don't know the type, then I ask the IDE or REPL what it is. Problem solved; everyone happy.
This is more of a problem when writing short functions (it increases the overhead both timewise and resulting noise) or when dealing with complicated types. I've dealt with types requiring 300+ character annotations. That's no fun. Or particularly when there are certain traits or other constraints that you haven't fully worked out. Making you figure them out on paper and write them down doesn't benefit anyone - they're required for a real reason and the compiler will always check and let you know.
You mean on function parameters and stuff? Never going to happen, and most of us would not count that as a "fix". If anything that makes programs harder to read, since tracking a type becomes much, much harder.
Furthermore, the forthcoming work on incremental recompilation intends to leverage the fact that function signatures are infallible in order to enable drastically improved incrementalism (no need to even consider recompiling code that calls a function if only the body of the called function changes), and the same fact will be leveraged to enable huge parallelism in incrementally compiled units.
Furtherfurthermore, Rust deliberately doesn't employ Hindley-Milner and so I'm not even 100% certain that whole-program type inference is feasible.
This makes the edit/fix syntax cycle 20x faster.
A way to configure this in vim: https://www.reddit.com/r/rust/comments/3kc6s7/fastest_editco...
meteor-contest Rust #2, 545 lines of code, 4.75s to build
http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...
I do see what you mean.
$ time /usr/local/src/rust-1.3.0-x86_64-unknown-linux-gnu/rustc/bin/rustc meteor.rs -o meteor.rust-2.rust_run
real 0m2.042s
user 0m1.940s
sys 0m0.096s $ time /usr/local/src/rust-1.3.0-x86_64-unknown-linux-gnu/rustc/bin/rustc threadring.rs -o threadring.rust_run
real 0m1.466s
user 0m1.340s
sys 0m0.112s"Bottom up (since the worst offenders are now first),
binary-trees is silly since it measures allocation speed for a case that simply doesn't exist in real code;
thread-ring is basically insane, since nobody ever bottlenecks like that;
chameneos-redux's C++ implementation is ridiculous. The C is not so ridiculous, but you still have the problem that basically every language in the top few spots does something completely different;
pidigits tests whether you have bindings to GMP;
regex-dna tests a regex engine on a small subset of cases (arguably the first half-acceptable benchmark);
k-nucleotide tests who has the best hash table for this particular silly scheme, and they don't all even do the same thing (eg. Scala precompacts, like my new Rust version);
mandelbrot is kind'a OK;
reverse-complement would be kind'a OK if not for a few hacky implementations (like the Rust);
spectral-norm is kind'a OK;
Haskell basically cheats fasta (which is why I copied it);
meteor-contest is too short to mean anything at all;
fannkuch-redux is probably kind'a OK,
n-body is kind'a OK.
So maybe 5/13 are acceptable, and I'd still only use 4 of those. I think if looking at mandelbrot, spectral-norm, fannkuch-redux and n-body you can argue the benches are a reasonable measure of peak performance. However, these cases are also all too small and simple to really be convincing either, nor is it particularly fair (where's NumPy for Python?)."
https://users.rust-lang.org/t/blog-rust-faster/3117/12?u=acc...
Have you looked at the benchmarks game website?
Please show where the benchmarks game website claims that those tasks simulate "real workloads" (whatever that means).
You will see "Your application is the ultimate benchmark" and "These are just 10 tiny examples" and …
http://benchmarksgame.alioth.debian.org/dont-jump-to-conclus...
When Veedrac dismissively tells you - "pidigits tests whether you have bindings to GMP" - you should ask why he hasn't told you that the measurements can be different even when all the programs use GMP; you should ask why he hasn't told you that the measurements also show the difference for the same language implementation when programs do and don't use GMP.
etc etc
I've been meaning to work on a proper "Erlang/OTP-ish" framework for Python for a long time, Pulsar[1] is a good start but needs more developers, and more documentation in order to grow. It has an example that does web sockets with normal Django, no massive hacks. (Which someone more familiar with Django should really check out and talk about more widely) But no Flask example?
Rust's original M:N threading almost begged for an OTP-style approach (as in, it looked like Erlang with a non-Prolog syntax :-)). But I think the current threading interfaces are pretty welcoming for an OTP style. Anyone working on that?
You might see some boring programs.
You could always contribute some boring programs ;-)
Most submitters try to optimize for speed, and to use smart tricks you need more LOC, so usually the shortest program is the more straightforward.
Actually, in this site they don't measure the size of a program in LOC, they use the size of the compressed program that is a better metric.
(It may be different in other sites specialized in code golf, because in the those sites the submitters are specializing for size specifically.)
Speaking of Rusts' HashMap, the Robin Hood map is pretty darn sweet (and I say that as someone who translated a Pythonish map to Rust), but the last time I looked it was still throttled by SipHash.[1] Is there any progress on SIMD-ing that?
[1] "Safety vs. performance", etc., etc.