Re: Optimizing libpng encode time
Adam Richter <[email protected]> Mon, 31 Aug 2020 23:40:44 -0700
| Newsgroups | gmane.comp.graphics.png.devel |
|---|---|
| Message-ID | <CAGn-Tgj4ig9t05ozKPchuOYi952aPE4Wen4QRmsfuK-DD6trww@mail.gmail.com> |
On Sun, Aug 30, 2020 at 8:03 AM Bob Friesenhahn <[email protected]> wrote: > > On Sat, 29 Aug 2020, Adam Richter wrote: > > but I need to fix the no-filtering build. Unfortunately, I am seeing > > almost know speed up, even though completely commenting out the memcpy > > that all of this is trying to avoid, or making it copy only, say, > > every even row, results in an unbelievable speed-up of over a factor > > of 10 (for no memcpy) for the 4488x3508 image I used in the benchmark > > above. if it turns out that that memcpy avoidance is not a real > > optimization, these changes may make it easier to do some thread-level > > parallelization with OpenMP ("#omp pragma parallel for"...). > > It would be good to use a high-quality profiler which can show the > time spent in CPU stalls due to waiting on memory. This can be > extremely illuminating. > > In today's systems, all application memory is initialized by default > in some way because otherwise your process would see private data from > the kernel or some other process. Some kernel thread is initializing > this memory. If the kernel thread runs on the same core as your own > code, then the memory will already be pretty "hot" in the caches. > Perhaps there may be hardware-specific tricks to know if a memory page > is initilized to a particular state (e.g. already zero). Memory > freshly allocated using mmap() will behave differently than recycled > "heap" memory which was already used by the same process. > > Regardless, if the memcpy is small and done in a L1 or L2 cache > without contention, then it may be insignificant compared to other > factors. Hello, Bob and other libpng developers. I think the speed-ups that I saw from commenting out copying of the input rows or only doing the copy in a fraction of cases were because that had the side effect of passing very simple data to libz. In my code, keeping everything else the same and just commenting out the call to png_compress_IDAT resulted in similar speed-ups of about 40X for the larger of the two examples I gave. So, the filter selection code appears not to be that much of the CPU cost. The silver lining on this is that when I compare the stock libpng code to mine, commenting out that call to png_compress_IDAT in both, mine seems to go about 4.5X faster for that 4488 x 3508 image ("gm convert" from pnm to png, both old and new compiled with "-O3"): 782.5ms vs. 166.5ms, although this is a small fraction of the total 6.6415 seconds average run time for my version with the call to png_compress_IDAT in place. So, so far, I still recommend merging my change or something along those lines, although I expect if I continue to look into optimizing libpng, it will be from png_compress_IDAT and the functions it calls, which probably means looking at optimizing zlib, such as porting in some techniques used in pigz. By the way Bob, I read the web page about zstd that you mentioned and I also tried "valgrind --tool=cachegrind gm convert ..." on a smaller file. So, thanks for the input, which i expect I'll use in the future. Adam