Optimizing Ray Tracing in Haskell
medium.com
medium.com
It sort of shows that in even simple functions such as this, underlying implementation details can have an impact on performance.
Also, for some reason filling a C array in Haskell was faster than doing it in C, probably due to the switching between RTS.
[0] https://github.com/siraben/functional-images
[1] https://github.com/sbond75/OpenGLTesting/commit/116384edd6a3...
[2] https://hackage.haskell.org/package/base-4.14.0.0/docs/src/G...
If you're not familiar its a (in development) exposed pipeline (static scheduling) VLIW ISA - not unheard of in DSP land but genuinely alien compared to a CISC scalar processor a la X86 or ARM. I'm not particularly optimistic about their chances of making into the shops but they haven't failed yet.
Cite? I've been looking for recent updates and haven't found any.
Not exactly busy but there you are
Just googled branchless programming :)
> A straightforward Rust implementation
(emphasis mine) and the implementation in the article is heavily optimized.
I would say that if an experienced Haskell programmer set out to write this program with the intent of making it fast, they'd never use lists in the first place, and not consider their absence an optimisation. Haskell lists are designed for lazily-generated arbitrary-length sequences, and are a bad fit for representing small finite-length sequences, such as vectors.
There is actually a fairly simple C++ version that was made as part of the original book. It also does a lot that is naive from a performance standpoint, but that's what I would think people would want to use a baseline.
It's pretty awesome what GHC can pull off in terms of reducing complex programs to a minimal normal form (you can see this with e.g. https://hackage.haskell.org/package/ghc-proofs-0.1.1/docs/GH... ), but often times you do have to convince the optimizer to be more aggressive than it wants to be.
"Fast enough to not be worth complaining about" is nowhere near anyone's TODO list.
You are until somebody makes one faster. Then, you're slow again. That is our deal with the Devil: our machines are filled with dodgy gimcracks that often make our program faster, but we can hardly ever know whether it as as fast as it could be, or if some gimcrack that would make it faster hasn't engaged yet; or, often, even how to go about engaging it.
Usually we stop optimizing when it seems fast enough, usually because something else is (still) slower.
It turns out to be pretty simple to make quicksort go twice as fast on current hardware. Standard libraries and compilers generally don't do those things, often out of fear of making a few programs slower than before. People complain a lot more about a slower program than they thank you for making a hundred others faster--if they even notice the latter.
When it gets to 93 seconds it is doing 208 GB of heap allocation and in the final version it is still doing over 20 GB of heap allocations. This seems like quite a bit for a 384x216 image.
If anyone knows the exact reason for that, then please enlighten me as well. Even this otherwise awesome tutorial ignores that value: https://youtu.be/R47959rD2yw?t=1306
1) If it allocates, why does `top` not show it?
2) Why does it allocate SO MUCH when it uses only a fraction? Looks like a very bad strategy to allocate 2800 times more memory than actually used?
When optimizing, excess heap allocations are the first thing to look at, since they are usually inside inner loops, which almost always means they are not necessary. It definitely should not be ignored by someone looking for speed.
That sounds interesting and will probably make it more efficient. But how do I put things on the stack? As per this answer on Stackoverflow, the runtime allocates memory on the heap to call functions (and probably programmers don't have any control over that?):
Yup. I know it's easy and the default behavior in C++.
This Haskell page says, it is pretty common to allocate and deallocate memory immediately, and that GHC handles this pretty efficiently, which probably explains why Haskellers dont seem to care about this (though it seems weird to me).