Where the flop count stopped predicting the time

One column of room past the edge

A recursive LU cut at multiples of the cache's edge leaves one short leaf per dimension, and the one-column leftovers cost the most. Folding the leftover into the leaf beside it puts that leaf one column past the edge, where every leaf at once costs two and a half times the pure recursion — so the prediction was that folding loses at 256 words and wins only where there are many leaves. It wins at every memory, on every one-column size, and wins more where the leaves are fewer: 0.021 of the pure recursion's traffic at 64 words, 0.074 at 400, bringing the short sizes down among the sizes with no leftover at all. Folding two columns loses everywhere, by up to three quarters. One leaf product says why: the edge is set by the cube, and a leaf wider in one dimension has exactly one column of room.

Worth reading first: The same arithmetic at a different price · The recursion that was never told the memory.

The short leaf belongs at the bottom settled where a recursive LU’s one short leaf should go. The recursion cuts every dimension at a multiple of the cache’s edge — M−2\sqrt{M} - 2 columns, the width a block size is a property of the machine found to be the cheapest leaf at every memory it scanned — so that every leaf is exactly the edge wide except one leftover per dimension. Cut off last, at the bottom of the recursion, the leftover is cheaper than cut off first. But it still costs: at 256 words the one-column sizes 99, 113 and 127 moved 0.90 to 0.95 of the pure recursion’s words against 0.85 to 0.90 for the sizes with nothing left over. And the same essay measured the edge’s other side. With the base case one column past the edge — every leaf a column too wide — the aligned cut’s median size costs two and a half to three times the pure recursion.

Its last section proposed the obvious repair and predicted it would fail. “A cut that absorbs a one-column leftover into its neighbour makes one leaf a column wider than the edge — one leaf on the cliff instead of a narrow one off it. The width sweep’s cliff is a factor of two for a leaf one column too wide, but one leaf of eight is an eighth of the traffic, and the prediction with a sign is that folding loses at 256 words and wins only where the leftover is one column and the leaf count is large.”

Folding wins at 256 words, and at every other memory, and it wins most where the leaves are fewest. The premise was that a leaf one column past the edge is on the cliff. It is not, unless it is past the edge in every dimension at once.

The fold, and what stays the same

The setting is the earlier essays’, the one the same arithmetic at a different price set up to compare two orderings of one elimination. A recursive LU with partial pivoting is run against a counted memory: one fully associative cache of M words with least-recently-used replacement, every word fetched from memory counted. The factorisation, the triangular solve and the trailing product are each cut along their largest dimension until the leaves fit the base case, and the leaves are done by plain loops. The test matrix is diagonally dominant, so every ordering of the elimination chooses the same pivots, and on every run the multiply-adds and the permutation are checked against the pure recursion’s: the arithmetic and the answer are identical, and only the traffic differs.

The new cut differs from the aligned one only when a dimension’s leftover is short. The aligned cut divides a dimension of x columns at the multiple of the edge b nearest its middle, so the leftover x mod bx \bmod b ends up as the last leaf. The folded cut divides x−(x mod b)x - (x \bmod b) that way instead, so the leftover rides on the last full leaf, which is then bb plus the leftover wide, and the recursion treats that one widened leaf as a base case. It folds a leftover of one column; a second version folds one or two. Four memories are measured — 64, 144, 256 and 400 words, edges of 6, 10, 14 and 18 columns — on every size from 96 to 127 columns whose leftover is one or two.

One column folded is cheaper everywhere

Sizes whose leftover is one column, cut off last and folded, beside the sizes with no leftover at all, at four memoriesWords over the pure recursion's, one dot per size. 64 words: no leftover 0.789, 0.800, 0.795, 0.787, 0.798, 0.809; one column last 0.807, 0.814, 0.806, 0.800, 0.811, 0.821; folded 0.783, 0.791, 0.784, 0.779, 0.791, 0.802. 144 words: no leftover 0.828, 0.817, 0.813; one column last 0.856, 0.831, 0.843; folded 0.812, 0.792, 0.798. 256 words: no leftover 0.903, 0.847, 0.863; one column last 0.947, 0.898, 0.902; folded 0.883, 0.846, 0.855. 400 words: no leftover 0.984, 0.978; one column last 1.049, 1.024; folded 0.966, 0.960.the folded sizes join the full ones64 words: folded best over no-leftover best0.99144 words: folded best over no-leftover best0.97256 words: folded best over no-leftover best1400 words: folded best over no-leftover best0.980.750.80.850.90.9511.05words ÷ the pure recursion's64 words144 words256 words400 wordsno leftoverone column, lastone column, foldedeach dot: one size from 96 to 127folded, the short sizes stop being short
Fig. 1 Words moved by the recursive LU on sizes whose leftover is one column, cut off last and folded into its neighbour, beside the sizes with no leftover at all, at four memories.

The figure above holds the whole result for one-column sizes. At each memory three groups: the sizes with no leftover, the one-column sizes with the leftover cut off last, and the same sizes folded. At 256 words the folded sizes 99, 113 and 127 move 0.883, 0.846 and 0.855 of the pure recursion’s words, against 0.947, 0.898 and 0.902 with the leftover last, and against 0.903, 0.847 and 0.863 for the sizes 98, 112 and 126 that have no leftover at all. Folded, the short sizes stop being short. At 400 words the two one-column sizes, 109 and 127, go from 1.049 and 1.024 — more traffic than the pure recursion — to 0.966 and 0.960, below the sizes with no leftover, which sit at 0.984 and 0.978.

Words a recursive LU moves over the pure recursion's at 256 words, on every size whose leftover is one or two columns, with the leftover cut off last or folded into its neighbourBase case the edge of 14 columns, cuts at multiples of it. One-column sizes: 99 from 0.947 with the leftover last to 0.883 folded, 113 from 0.898 with the leftover last to 0.846 folded, 127 from 0.902 with the leftover last to 0.855 folded. Two-column sizes, folded into a leaf two past the edge: 100 from 0.939 to 1.458, 114 from 0.897 to 1.357.256 words, edge 14one column: median saving0.051two folded: median extra0.49961001041081121161201241280.811.21.4columnswords ÷ the pure recursion'sleftover lastone column foldedup to two foldedhorizontal line: the pure recursionone column fits, two do not
Fig. 2 Every size from 96 to 127 whose leftover is one or two columns, as words over the pure recursion’s, with the leftover cut off last, one column folded, and up to two folded. The dial sets the fast memory.

The dial runs the comparison at every memory. At 64 words, edge six, the six one-column sizes save about two hundredths each: 97 from 0.807 to 0.783, 127 from 0.821 to 0.802. At 144 words the three save four hundredths. At 256 the three save five, and at 400 the two save six and eight. On every one-column size at every memory, the folded cut moves fewer words than the leftover-last cut, with the same elimination underneath.

How much folding a one-column leftover saves, against the size of the fast memory, with the number of full leaves each dimension hasThe difference between the words the leftover-last cut and the folded cut move, as a fraction of the pure recursion's, on every one-column size from 96 to 127: median with the range. 64 words, 6 sizes, about 16 full leaves a dimension: median 0.021, from 0.019 to 0.024; 144 words, 3 sizes, about 10 full leaves a dimension: median 0.044, from 0.039 to 0.045; 256 words, 3 sizes, about 7 full leaves a dimension: median 0.051, from 0.047 to 0.064; 400 words, 2 sizes, about 6 full leaves a dimension: median 0.074, from 0.064 to 0.083.one column folded64 words, 16 leaves: median saving0.021144 words, 10 leaves: median saving0.044256 words, 7 leaves: median saving0.051400 words, 6 leaves: median saving0.07410020030040000.020.040.060.080.1fast memory, wordssaving ÷ the pure recursion's words16 leaves10 leaves7 leaves6 leavesbars: every one-column sizefewer leaves, larger saving
Fig. 3 The saving from folding a one-column leftover, as a fraction of the pure recursion’s words: median and range over the one-column sizes at each memory, with the number of full leaves a dimension has.

The prediction tied the saving to the number of leaves, on the reasoning that one wide leaf among many is a small share of the traffic. The saving runs the other way: 0.021 at 64 words, where a dimension of a hundred columns has sixteen full leaves, 0.044 at 144 with ten, 0.051 at 256 with seven and 0.074 at 400 with six. The reasoning priced the wide leaf as a cost to be diluted. It is not a cost. What folding removes is the narrow leaf, and a narrow leaf’s cost is set by how much wider the edge is than one column — six times at 64 words, eighteen at 400 — so the larger the edge, the more a one-column leftover was wasting and the more folding recovers.

Two columns folded is over the cliff

The second version folds a leftover of two columns as well, so the widened leaf is two past the edge. It loses on every two-column size at every memory. At 64 words the five two-column sizes go from about 0.80 to about 0.90; at 144 words from 0.82–0.86 to 1.07–1.14, above the pure recursion; at 256 from 0.94 and 0.90 to 1.46 and 1.36; at 400 the one two-column size, 110, goes from 1.042 to 1.766. The dial shows the two-column dots climbing away from the others as the memory grows, while the one-column dots fall beneath them.

So between one column of overhang and two, the cut goes from the best thing measured on these sizes to the worst. That is a cliff, but it is not where the earlier essay placed it. One column past the edge in every leaf was over it; one column past the edge in one leaf per dimension is not; two columns past the edge in one leaf per dimension is. The question is what a leaf’s width is measured against.

What one leaf product can hold

The recursion’s traffic is the sum of its leaves’, and a leaf is a product C−=XYC \mathrel{-}= XY with C of m×qm \times q, X of m×km \times k and Y of k×qk \times q, done by three loops, rows of C outermost. Running one such product three times through the same cache and counting what its third pass fetches gives its price when the recursion reaches it warm, with nothing else in the way.

Words one warm leaf product fetches per multiply-add, at the edge and with each dimension one or two past it, at four memoriesA product of an m by k block and a k by q block into an m by q block, in the base case's loop order, run three times through a least-recently-used cache: the third pass's words over its multiply-adds. 64 words, edge 6: at the edge 0.333, rows one over 0.333, inner one over 0.310, columns one over 0.310, rows two over 0.333, inner two over 1.229, columns two over 1.229, all three one over 1.245. 144 words, edge 10: at the edge 0.200, rows one over 0.200, inner one over 0.191, columns one over 0.191, rows two over 0.200, inner two over 1.158, columns two over 1.158, all three one over 1.165. 256 words, edge 14: at the edge 0.143, rows one over 0.143, inner one over 0.138, columns one over 0.138, rows two over 0.143, inner two over 1.121, columns two over 1.121, all three one over 1.124. 400 words, edge 18: at the edge 0.111, rows one over 0.111, inner one over 0.108, columns one over 0.108, rows two over 0.111, inner two over 1.097, columns two over 1.097, all three one over 1.100.0.10.20.51words per multiply-add, logarithmicat the edgerows one overinner one overcolumns one overrows two overinner two overcolumns two overall three one over64 words144 words256 words400 wordsone leaf product, warmone column of slack, not two
Fig. 4 Words one warm leaf product fetches per multiply-add, at the edge and with its rows, its inner dimension or its columns one or two past the edge, or all three one past, at each memory.

At the edge the product fetches 2/b2/b words a multiply-add — 0.333 at 64 words, 0.143 at 256, 0.111 at 400 — which is C and X brought in once a pass while all of Y stays in cache. Widen the rows by one or two and nothing changes per multiply-add: the rows of C and X stream through and Y still stays. Widen the inner dimension or the columns by one and the product gets slightly cheaper, 0.138 instead of 0.143 at 256 words: more work for the same pass over C and X. Widen either of them by two, or all three dimensions by one, and the product fetches 1.10 to 1.25 words a multiply-add at every memory — about every operand, every time. Y no longer stays.

The count behind it is the size of what has to stay. With rows outermost, the working set is the block of Y, kqkq words, plus a row of X and a row of C, k+qk + q more. At the edge, b=M−2b = \sqrt{M} - 2 in all three dimensions, that is M−2MM - 2\sqrt{M}: two edges’ worth of words to spare. One dimension a column over takes about M\sqrt{M} of them and leaves about M\sqrt{M}; that is enough. Two columns over in one dimension, or one over in both kk and qq, leaves one or two words — M−2M - 2 and M−1M - 1 — and a least-recently-used cache that must also bring in the next row before the last one leaves cannot do it. The rows, mm, are not in the count at all.

So the edge, M−2\sqrt{M} - 2, is the widest cube that fits — the widest leaf that can be that wide in all three dimensions — and the room it leaves is one column in one dimension. A recursion whose leaves are all one column past the edge is past it in all three, every time two such leaves meet in a product, and that was the earlier essay’s cliff. The recursion that was never told the memory measured the pure recursion within 0.94 to 1.28 times the best tuned block at every memory; the fold is one more place where telling it the memory, to the column, is worth a few per cent. A folded leaf is one column past in one dimension of most products it takes part in. It meets another widened leaf in the same product only where the last leaves of two dimensions cross, at the bottom-right corner of the factorisation.

The fold also takes the leftover’s calls away

Words are what the counter measures, and the earlier essays measured nothing else. The message and the word made the same distinction between a distributed code’s volume and its count of exchanges, and found the method with the fewest exchanges sending the most words. The recursion’s calls are a second cost, the one a real machine pays in function entries and loop set-ups, and the fold changes them too. A one-column leftover is a dimension that never stops being cut until it reaches a one-wide piece: it adds a level of products along every edge of the recursion that touches it. Folded, the leftover rides on a leaf the recursion treats as a base case, and those products are never made.

At every memory the folded one-column size makes no more calls than the size one column smaller, which has no leftover at all: 97 columns at 64 words make 2,675 calls folded against 2,686 for 96 columns, and 3,219 with the leftover cut off last; 99 at 256 words make 218 folded, 220 for 98, and 330 with the leftover last; 109 at 400 words make 136, 138 and 220. The leftover-last cut makes an eighth more calls than the folded one at 64 words and more than half again as many at 400 — the same pattern as the words, for the same reason: the wider the edge, the more a one-wide piece multiplies what has to be cut. The block size a recursion still has found the recursion’s traffic stepping at the halvings of n; the leftover is one more halving the fold removes.

Why the prediction priced it backwards

The prediction took the cliff as a property of a leaf: a leaf one column too wide costs about twice what it should, and one such leaf among eight costs an eighth of that. Measured on a leaf product, a leaf one column too wide in one dimension costs nothing extra at all; the factor of two belonged to products whose every dimension was too wide. And the narrow leaf the fold removes is the expensive thing. A one-column leftover turns into a one-column panel at the bottom of the factorisation and a one-wide strip in every product that touches it — the shape whose words per multiply-add are worst — and leaves cut to the edge on purpose found those strips costing the one-column sizes five hundredths of the pure recursion’s traffic that the sizes with no leftover did not pay. The fold recovers all of it and a little more, because the widened leaf is itself a slightly better leaf.

The leaf that sits on the edge found no trade between a processor that wants wide leaves and a cache that wants narrow ones: at every width the cheapest leaf in words was the widest that fitted. The fold is that rule applied to one dimension at a time. The widest that fits in all three is the edge; the widest that fits in one, with the other two at the edge, is one column more.

What this changes in the rule

The rule the earlier essays arrived at was: set the base case at M−2\sqrt{M} - 2, cut every dimension at multiples of it, and cut the leftover off last. The measurement adds a clause. A leftover of one column is folded into the last full leaf; a leftover of two or more is cut off last. With that clause the one-column sizes, which were the worst sizes under the old rule, come within two hundredths of the sizes with no leftover at 64 and 144 words and fall below them at 256 and 400.

The words a recursive LU moves at 256 words of fast memory, against how far its base case is from the edgeThe median over sizes 96 to 127, with bars from the lowest size to the highest, of each cut's words over the pure recursion's, for base cases from three columns under the edge to two over. With the aligned cut the median is 0.903 one column under the edge, 0.886 at it and 2.876 one column over; halving's median is 1.046, 0.919 and 0.917, and its worst size one column over is 3.15.256 words, base 14 at the edgealigned, one under: median0.9aligned, at the edge: median0.89aligned, one over: median2.9-3-2-101211.522.533.54base case's offset from the edge, columnswords ÷ the pure recursion'shalving to the edgealigned, leftover lastaligned, leftover firstvertical line: the edge · bars: lowest to highest sizeno margin on the far side
Fig. 5 The earlier measurement of the edge misjudged: the median and range over every size from 96 to 127 of each cut’s words over the pure recursion’s, against how far the base case is from the edge, at 256 words.

The clause depends on the edge being known to the column, and that figure is why. The aligned cut is cheapest at the edge or just under it, and one column over it the median size costs nearly three times the pure recursion: every leaf is then past the edge in all three dimensions of every product, the case the leaf product above puts at a word per multiply-add. An edge overestimated by one would also turn the fold’s one column of room into none — the folded leaf would be two past the true edge, the configuration measured above as the worst on the page. The count suggests that a code unsure of its edge by a column should take the lower estimate and fold, which keeps the fold’s room and costs the narrower leaves a few per cent; that is the count’s suggestion, and it is not measured here.

What the counter does not see

The memory is one level, fully associative, with exact least-recently-used replacement and lines of one word. A real cache moves lines of eight words or more and is set-associative, and both change where the cliff falls: a line size turns the count’s single-word margins into margins of a line, and an associativity limit can put the cliff earlier for a block whose rows map to the same sets. The leaves are done in one loop order; a leaf kernel that keeps C in registers and streams Y would have a different count and its own room. And the sizes are 96 to 127 columns — large enough for a few levels of recursion, small enough that the bottom-right corner where two folded leaves meet is a visible share of the work. At thousands of columns that corner is negligible and the fold’s saving per size would be the narrow leaf’s cost alone.

Still open: a cliff with a line size, and a leftover split across leaves

The cliff with a line size. The earlier essay’s second question stands, and the leaf count makes it sharp. With lines of eight words a row of X or C costs a line for every eight of its words, the margin left by one extra column is M\sqrt{M} words but only M/8\sqrt{M}/8 lines, and a fold’s room may vanish. The prediction with a sign is that at 256 words with lines of eight words the folded leaf still costs within a tenth of the edge leaf, because the margin it uses is less than a line per row, and that the two-column fold is still over the cliff — so the rule’s clause survives the line size unchanged.

A two-column leftover split between two leaves. Folding two columns into one leaf is over the cliff, but two columns folded one into each of the last two full leaves would put two leaves one column over in different places. The prediction is that this wins on every two-column size at every memory, by about the one-column saving, unless the two widened leaves meet in a product — which happens when they are adjacent, and so the two columns should go into leaves that are not neighbours.

Shares its objects with

Essays that name at least two of the same things, and that neither author linked.

Named objects

A flat tag is an object no other essay names yet.

Blocked algorithmCacheData movementFlop countLU factorisationMemory hierarchyRecursive factorisation