Sometimes, rewriting in another language works
espadrine.github.io
espadrine.github.io
Still, at the same time, we can judge a language based on how easy it is to fall into the pit of success rather than the pit of failure; if their Julia code had a problem, then maybe the Julia developers could tweak some defaults (or change some documentation) so that people in the future do not fall afoul of the same result. The same sort of thing exists in Rust as well, where the fact that I/O is unbuffered by default makes it perform poorly in microbenchmarks that involve printing a zillion times in a loop: https://nnethercote.github.io/perf-book/io.html#buffering
This may be surprising to people coming from C or C++, where unoptimized code is slower but not that slow. But the point of Rust is that it's selectively provided as many zero-cost abstractions as it can, which when paired with a modern sufficiently-smart backend like LLVM boils away those abstractions into nothing. It's a great feeling the first time that you crack open the assembly output for a highly abstract chain of iterator/closure chains only to find that the whole shebang has been reduced to a handful of fixed-form arithmetic operations without a loop or a function call in sight. But the tradeoff is that you do have to perform the step of boiling those abstractions away.
Quite interesting paper, in case you haven't read it, "An Overview of the PL.8 Compiler"
https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.453...
Unfortunately despite its internal success they decided to go with Aix for RISC.
AFAIK, all of them will do some register assignment, some constant folding, etc.
For example, if you write
void f(int a)
{
int b = a;
b = b + b;
g(b);
}
are there compilers out there that compile that to - load a
- store into b
- load b
- load b into another register
- add
- store into b
- load b
- call g
- return
?Languages that do overflow and range checks such as Julia and Rust in debug mode would have to add lots of them there if they do not do any optimization.
I'm glad Zig is providing some competition here that's more in line with what one would expect from C.
I too had the "Un-optimized Rust code is slow!" experience when I started out, because my first project required PNG encoding and decoding, and the png crate was incredibly slow without optimizations.
But it's typical for C and C++ to be un-optimized at the level of `main`, but calling into heavily-optimized system libraries like ffmpeg.
https://media.discordapp.net/attachments/386246790565068811/...
Although it's worth mentioning that LLVM understands math and might be replacing an inefficient sum calculation with an efficient algorithm, so it might not be all down to codegen.
A tradeoff in the separate direction, though, is compilation performance. Currently the master branch takes 15 minutes to compile in release mode. It’s probably due to the hardcoded root choices, and I assume compilation is faster if they are loaded from a string instead of a structure, but it is a bit of a gotcha.
The commit which hardcodes them in is the one that starts having slow compilation: https://github.com/espadrine/optimal-wordle/blob/2e71cb4ca46...
It is possible that there is a recommended way to do it differently which I missed. I tried lazy_static!, but ended up having to fight the type system, and the related GitHub issues didn’t bring me hope that I could overcome it easily.
pub struct Choice {
pub word: String,
pub avg_remaining: f64,
}
pub fn root_choices() -> Vec<Choice> {
vec![
Choice { word: "roate".to_string(), avg_remaining: 60.42462203023758 },
with this: use std::borrow::Cow;
#[derive(Clone)]
pub struct Choice<'a> {
pub word: Cow<'a, str>,
pub avg_remaining: f64,
}
pub const ROOT_CHOICES: &[Choice] = &[
Choice { word: Cow::Borrowed("roate"), avg_remaining: 60.42462203023758 },
and it brought the time of `cargo clean && cargo build --release` down from 345 seconds to 13 seconds. I consider this a compiler bug, I'll file it if I can't find an existing issue.That's... very surprising; And it's hard to take this seriously unless you provide some justification for this claim.
function match_constraint(word::String, constraint::Constraint)::Bool
if constraint.type == has_no
constraint.letter ∉ word
elseif constraint.type == has_but_not_at
(constraint.letter ∈ word) && (word[constraint.index] != constraint.letter)
elseif constraint.type == has_at
word[constraint.index] == constraint.letter
end
endThis is also what the rust version does.
I'm not sure what to conclude given the title of this post. Rewrites often improve things greatly. But a 2 hour time investment is not what anyone is talking about when they repeat mottos like "never rewrite."
It’s hard to assess to which extent the performance tweaking vs. rewriting tradeoff scales up. For a larger project, the rewrite could take a month; but maybe, diminishing returns helping, the performance tweaking would plateau short of a month.
So, vcat() instead of append!(). Darn. Faith in Julia restored. I’ll update the article.
https://discourse.julialang.org/t/rust-julia-comparison-post...
So far, a bug fix improves it 4700 min -> 150 min, changing the type stored -> 20 min, further optimisations -> 15 min.
Non-optimally written julia code is as slow as non-optimally written code in any other language. Simply expecting code to be super optimised just because you wrote it in Julia instead of language X, and putting zero effort in taking advantage of Julia's advanced features that actually result in that optimality is just plain silly.
Edit: This is like saying people has to stop saying Ferraris are fast, because you can still drive slow in them
You want your Ferrari to go fast? Drive it like a Ferrari.
Also, Python absolutely can be as performant as Julia, if not more. The point is that Julia has language-builtin features that were created with this performance in mind, whereas for Python you have to go explore the relevant package ecosystem and go down a numba/cython/pypy/etc route.
And, yes, if you bragged how a Fiat could never beat your Ferrari in a race, and you agreed to race me against my modified Fiat with external turbo engines and I beat the crap out of your Ferrari, your "well that wasn't really a Fiat" complain would be valid, but only so much. Especially if Fiats were super-moddable by nature.
There's no need for them to be "written in pure python". They just need to be seemlessly usable from within it.
https://www.google.com/search?q=%22Julia+is+the+fastest+high...
Please have some intellectual honesty or share some links as apparently you know where to find some things that Google does not know about.