9b9dc9590258144d7b7f17d1ecafb674d2d86956
braney
  Wed Sep 2 13:26:40 2026 -0700
pngLevelBench: sweep the row filter as well as the level, refs #38109

The filter and the level interact, and #38107 picked the filter at the default
level only, so measuring one with the other pinned answers half a question.
pngLevelBench now takes -filters and -baseFilter, its -tab output carries a
filter column, and everything is compared against the pair the browser ships,
up at level 6.  levelReport.py reads the new column and still accepts rows
written before it existed.

Two scripts around it grew what a second, larger corpus needed.  pickUrls.py
takes --seed and --exclude, so a later sample does not repeat an earlier one.
render.sh takes its arguments rather than a hardcoded directory, and renders
several at once; six in parallel is about seven a second against a ticket
sandbox, against one every eight seconds one at a time, and it changes nothing
that is measured, since the encode is timed offline afterwards.

diff --git src/hg/oneShot/pngLevelBench/README src/hg/oneShot/pngLevelBench/README
index 348253b15dd..aabf641b2dc 100644
--- src/hg/oneShot/pngLevelBench/README
+++ src/hg/oneShot/pngLevelBench/README
@@ -9,43 +9,58 @@
 Four pieces, in the order they run.
 
 1. pickUrls.py    pick a corpus of real hgTracks URLs out of an access log.
 
        zcat /hive/data/inside/wwwstats/RR/2026/hgw1/access_log.20260823.gz \
          | grep -a '"GET /cgi-bin/hgTracks?' | awk '{print $7, $9}' | gzip > gets.gz
        hgsql -N -e "show databases" > localDbs.txt
        pickUrls.py gets.gz localDbs.txt corpusUrls.tsv 300
 
    URLs are sampled in proportion to how often each was loaded, so the corpus
    is traffic weighted.  Custom track and hub URLs are dropped, since they
    reach off the machine, and so are assemblies this machine does not have.
 
 2. render.sh       render each URL against a parked hgTracks and keep the png.
 
-   Set PORT to the ticket sandbox.  It uses hgRenderTracks, which returns the
-   image itself rather than a page, and it sends an explicit pix= so the first
-   hit is a render and not addPixAndReloadPage().
+       render.sh corpusUrls.tsv corpus 48088 6
+
+   The port is the ticket sandbox's and the last argument is how many renders
+   to run at once.  It uses hgRenderTracks, which returns the image itself
+   rather than a page, and it sends an explicit pix= so the first hit is a
+   render and not addPixAndReloadPage().  Rendering in parallel changes nothing
+   that is measured later, since the encode is timed offline.
 
 3. pngLevelBench   encode each corpus image at every level, 0 to 9.
 
        pngLevelBench -tab -reps=3 corpus/*.png > bench.tsv
        pngLevelBench -check one.png            # the validation, see below
 
    The encode matches lib/pngwrite.c exactly: RGBA, 8 bits, no interlace, row
    filter pinned to UP.  Only the level varies, and nothing is written to disk,
    so the time is the encode alone.
 
+   The row filter can be swept too, since the two settings interact and the
+   filter that compresses best is not the same one at every level or on every
+   image:
+
+       pngLevelBench -tab -reps=2 -minLevel=1 -maxLevel=6 \
+           -filters=none,sub,up,avg,paeth,all corpus/*.png > sweep.tsv
+
+   `all` is libpng's own per row choice, which is what the browser did before
+   #38107 pinned UP.  Everything is compared against `-baseFilter` at `-base`,
+   which defaults to the pair the browser ships, up at 6.
+
 4. levelReport.py  aggregate into per-level B, S and break-even speed.
 
        levelReport.py bench.tsv logSizes.tsv 6
 
    logSizes.tsv is one real image size per line, from the same log:
 
        zcat access_log.*.gz | grep -a 'GET /trash/hgt/hgt_' \
          | awk '$9==200 && $10>1000 && $7 ~ /\.png/ {print $10}' > logSizes.tsv
 
    The `$7 ~ /\.png/` matters.  The same directory holds the mouseover .json
    files, which are small and numerous, and counting them drags every size
    percentile down.
 
 What makes the numbers trustworthy, and what does not
 -----------------------------------------------------