3 ms·
> TL;DR: What rust did in the follow up post also wasn't actually an optimization, in at least one microbenchmark. Interesting! This isn't a correct conclusion
by dbaupp 10y ago
> TL;DR: What rust did in the follow up post also wasn't actually an optimization, in at least one microbenchmark. Interesting!
This isn't a correct conclusion!
There's more differences between the code that just the optimisation enabled by the aliasing guarantees: hoisting the load outside the loop. The difference is likely to be the choice of the Rust compiler to use inc + cmp, instead of just dec like the C++ one does, which should be independent of the ability to hoist the load (indeed, if I change the Rust to use a while loop and manual incrementing, it results in using dec, and also hoisting the addition outside the loop to a multiplication, and similarly, if the 0..100 is changed to 0_i64..100, i.e. using 64-bit integers, the same hoisting happens... this looks like another case of LLVM not fully untangling Option<i32>).
If one was wanting to compare the actual quality of the generated code between two specific compilers, sure, but the intention is presumably to compare the actual "interesting" optimisation enabled by the language semantics.
Your conclusion would be correct if you got the same results after controlling for the other variables, i.e. make the C++ use inc & cmp, or the Rust use dec.
- MaulingMonkey 10y agoFair critique! I should perhaps not be benchmarking at 6AM. Fortunately it's no longer 6AM. > if the 0..100 is changed to 0_i64..100 I misread this initially as a complaint about the tweak to assembly iteration duration instead of a comment on tweaks to the author's Rust code (not enough caffeine). I did make the rust version worse by encoding a 64-bit immediate value in the inner loop's cmp, when the original was dealing with an 8-bit immediate value, so it's a fair complaint, even if you didn't make it ;). I've updated my code to attempt to correct for this deficiency as well. > Your conclusion would be correct if you got the same results after controlling for the other variables, i.e. make the C++ use inc & cmp, or the Rust use dec. V2: https://gist.github.com/MaulingMonkey/870c2fd1dc3e4f1b766199d05baf04b0 https://gist.github.com/MaulingMonkey/870c2fd1dc3e4f1b766199... Comparing: ..._rust vs ..._rust_ref, the only difference in the assembly is if I dereference inside or outside the loop. I've included two benchmarking passes of an identical program: In one, the version that dereferences inside the loop tends to actually perform faster (173ns vs 179ns per inner loop and setup/teardown thereof). In the other, performance tends to be identical: 173ns, the lower of the two. In-loop dereferencing performing better makes little enough sense to me that I'm inclined to err on the side of "this is neither an optimization nor a deoptimization", although the pattern is occuring regularly enough even with different stretch values that I'm really curious as to what's going on. EDIT: I believe I've figured it out - when comparing _cpp_deref vs _cpp (again, only difference being where I dereference, inside or outside the loop): Whichever I place further from stretch_benchmark / just_ret in foo.asm tends to be faster by up to 30ns. This applies to the rust versions too. I'm more likely measuring icache or similar than real performance differences between the two loops.
- dbaupp 10y agoGreat analysis. Thanks for following up. I guess you realise this, but the benefits of hoisting even simple operations like a dereference outside the loops is enabling other optimisations, such as the addition -> multiplication one here or even fancier like interchanging loops/ifs and vectorisation.