An Optimization Story
tinkering.xyz
tinkering.xyz
I was expecting the story to turn and show a huge ~100x coming from numpy, and surprised by the very small impact. That’s exactly what’s happened to me when I’ve switched image processing or simulations from raw python to numpy. Maybe I’m completely misunderstanding the problem, but it looks like the issue might be that numpy is not bubbled all the way up to be the outside of the main loop, maybe in this case on the outside of the entire spectrum calculation (if I’m understanding the problem at all). To see the real gains from numpy, you have to turn your program all the way inside out.
Just like you, I'm not really following the domain calculations, so maybe there's a reason that code can't be properly vectorized. But as others have commented, I'm a bit at a loss why the author didn't try numba or Cython.
> The [Rust to] Python interop was shockingly easy. I wouldn't even know how to begin doing this with C.
I do know how to do it with C. I would not describe it as "shockingly easy". It's not difficult either, but a type safe shockingly easy alternative is definitely worth a look.
For this though “one of the easiest ways to make a program faster is to make it do less work”. Correct me if I am wrong but isn’t that the only way to make programs faster? Do less work on a single core is the only method I have ever seen. Everything, from memory alignment to SIMD is just reducing the amount of steps. Would be happy to know an exception to this.
The code itself looks slow and barely readable. A lot of for loops, few named functions. It needs a very strong refactoring to work properly with numpy. That should be done first, instead of pulling up the RuStIsFast card. It is not surprising that the results were not so great as expected.
In general, the article is too long to be properly understood...
The most obvious (to me) is the constant indexing into pigs. It was hit on in the article (and gave a 25% increase in speed), yet I don't think the author went far enough in elimination.
Pushing the pig_j lookup up into the "for j" scope instead of computing it on each inner loop would have likely saved a large number of the lookups.
In fact, I'd guess that'd be one of the optimizations that rust pulls out. Python is far less likely to pull those sorts of optimizations.