Optimizing Common Lisp's png-read Library

Michael Fiano 2017-08-07 10:27:00 common-lisp

After many years frustrated with how slow Common Lisp's png-read library is, I decided to take an evening to try to optimize it. Here are the timing results of trying to parse a file from disk 1000 times with SBCL 1.3.19, for each of these sample images in PNGSuite.

Format Original Modified Ratio
Grayscale 1bit 0.190s 0.117s 1.62x
Grayscale 2bit 0.117s 0.077s 1.52x
Grayscale 4bit 0.119s 0.094s 1.27x
Grayscale 8bit 0.201s 0.118s 1.70x
Grayscale 16bit 0.287s 0.203s 1.41x
Grayscale/Alpha 8bit 0.426s 0.191s 2.23x
Grayscale/Alpha 16bit 0.946s 0.559s 1.69x
Indexed 1bit 0.202s 0.163s 1.24x
Indexed 2bit 0.217s 0.187s 1.16x
Indexed 4bit 0.221s 0.199s 1.11x
Indexed 8bit 0.267s 0.265s 1.01x
RGB 8bit 0.765s 0.283s 2.70x
RGB 16bit 1.291s 0.453s 2.85x
RGBA 8bit 1.035s 0.335s 3.09x
RGBA 16bit 1.848s 0.722s 2.56x

Particularly noticeable are the RGB and RGBA variants, with approximately 3x boost. I may continue to optimize more, but for a start I am definitely happier.

If you're interested, or you would like to help improve it even more, check out my fork on GitHub.

Update (8/7/2017): Changes have been merged upstream, so everyone can take advantage of the performance boost in the original version later this month when the latest Quicklisp dist is released.

Update (8/24/2017): I wrote a PNG parser completely from scratch that is even faster, and more featureful. Check it out here.