Optimizing Deconstructed Image. From art to Analytics (part I)
Deconstructed
Background of Deconstructed Image
Many of my contacts and friends are aware of my non-professional activity blending two of my passions: ๐ฎ๐ฟ๐ and ๐ฐ๐ผ๐บ๐ฝ๐๐๐ฎ๐๐ถ๐ผ๐ป. You might have seen my TEDx talk where I described how I was โpushedโ into the area of algorithmic art and Deconstructed Image. After some time developing an open-source 3D virtual gallery I decided months ago to get back to my image deconstruction project. It has been an incredible opportunity to practice one of my best skills: problem solving.
For those of you unaware, my algorithmic art project tries to reorganize the pixels of a digital image based on given loss function. It is a blantly untractable optimization problem, with a number of combinations beyond any reasonble unreasonable number, so it that can only be tackled from meta-heuristics approaches. Getting remarkable solutions imply running billions, trillions, quadrillion iterations. Sky is the limit.
Initial algorithm
Back to the initial algorithm development, done in ๐ ๐ฎ๐๐น๐ฎ๐ฏ, I was happy to reach (hardly) the 1 us per iteration benchmark. In the new develoment I was aiming to reduce the iteration time x10, in order to generate high resolution images. ๐พฬฒ๐ฬฒโฬฒ๐ฬฒ๐ฬฒ๐ขฬฒ,ฬฒโฬฒ๐ ฬฒ๐ฬฒ๐ฬฒ๐ฬฒโฬฒ๐ฬฒโฬฒ๐ฬฒ๐ฬฒ๐ฬฒ๐ฬฒ๐ฬฒ๐ฬฒ๐ขฬฒ. I will develop the story into several posts, but letโs see a high level overview:
- I started redesigning the code completely, still in Matlab, just to realize it was slower than before ๐ฃ. At least it created data structures that helped debugging it.
- Moving away from ๐ ๐ฎ๐๐น๐ฎ๐ฏ, I decided to learn ๐ ๐ผ๐ท๐ผ (the new compiled high performance Python). It proved me I could go beyond the 0.5 us mark. It is indeed fast but it was extremely frustrating to interpret the compiler errors and when an update changed the definition of pointers, I gave up. It needs to settle down and stabilize the code base.
- After thinking about C, C++, Rust or even good old Fortran, I decided to port the code to ๐++. I got close to 0.7 us/iteration. That was not enough so I learnt ๐บ๐๐น๐๐ถ๐๐ต๐ฟ๐ฒ๐ฎ๐ฑ๐ถ๐ป๐ด.
- I faced all the academic issues of multi-threading, from ๐บ๐๐๐ฒ๐ to ๐๐ฝ๐ถ๐ป๐น๐ผ๐ฐ๐ธ๐ and the producer-consumer problem. I hit a wall on the 0.4 us. I always thought that this was indeed a non-parallelizable problem and proved to be rather true. When it was not context switching, it was memory bandwidth or atomic variables overhead.
- Finally, I removed all the concurrent access code but kept all the optimizations created in the journey, to realize that the single-thread task could go around the 100 ns mark. Mission accomplished.
๐ข๐๐ต๐ฒ๐ฟ ๐ธ๐ฒ๐ ๐น๐ฒ๐ฎ๐ฟ๐ป๐ถ๐ป๐ด๐:
- ๐ฃ๐ผ๐๐ถ๐๐ถ๐๐ฒ ๐๐๐ฟ๐ฝ๐ฟ๐ถ๐๐ฒ๐: how much C++ has changed, the Tracy profiler (and VTune), CMake and Windows Subsystem Linux.
- ๐ก๐ฒ๐ด๐ฎ๐๐ถ๐๐ฒ ๐๐๐ฟ๐ฝ๐ฟ๐ถ๐๐ฒ๐: how tough is to debug multidimensional data in C++
- ๐๐๐ ๐ ๐ฒ๐ ๐ฝ๐ฒ๐ฟ๐ถ๐ฒ๐ป๐ฐ๐ฒ: for high-end algorithm development, it is not fit for the task. It is not a Phd coder but rather an assistant that does things well when micro-managed. (tbc)

Continue to part 2.