Repository: cockroachdb/pebble
Pull request #3655 (2024-06-11 13:53:11)

crl-release-23.2: db: more readable iterator stats
This change reformats the output of iterator stats which are very hard to read. We omit reverse counts when they are zero and remove redundant information.

We also show the cached and not-cached block bytes instead of the total and cached.

cockroach-teamcity: 

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/cockroachdb/pebble/3655)
<!-- Reviewable:end -->


Patch:
diff --git a/internal/base/iterator.go b/internal/base/iterator.go
index 8ab10a6c..c27cccc5 100644
--- a/internal/base/iterator.go
+++ b/internal/base/iterator.go
@@ -7,6 +7,9 @@ package base
 import (
 	"fmt"
 	"time"
+
+	"github.com/cockroachdb/pebble/internal/humanize"
+	"github.com/cockroachdb/redact"
 )
 
 // InternalIterator iterates over a DB's key/value pairs in key order. Unlike
@@ -407,3 +410,35 @@ func (s *InternalIteratorStats) Merge(from InternalIteratorStats) {
 	s.SeparatedPointValue.ValueBytes += from.SeparatedPointValue.ValueBytes
 	s.SeparatedPointValue.ValueBytesFetched += from.SeparatedPointValue.ValueBytesFetched
 }
+
+func (s *InternalIteratorStats) String() string {
+	return redact.StringWithoutMarkers(s)
+}
+
+// SafeFormat implements the redact.SafeFormatter interface.
+func (s *InternalIteratorStats) SafeFormat(p redact.SafePrinter, verb rune) {
+	p.Printf("blocks: %s cached",
+		humanize.Bytes.Uint64(s.BlockBytesInCache),
+	)
+	if s.BlockBytes != s.BlockBytesInCache || s.BlockReadDuration != 0 {
+		p.Printf(", %s not cached (read time: %s)",
+			humanize.Bytes.Uint64(s.BlockBytes-s.BlockBytesInCache),
+			humanize.FormattedString(s.BlockReadDuration.String()),
+		)
+	}
+	p.Printf("; points: %s", humanize.Count.Uint64(s.PointCount))
+
+	if s.PointsCoveredByRangeTombstones != 0 {
+		p.Printf("(%s tombstoned)", humanize.Count.Uint64(s.PointsCoveredByRangeTombstones))
+	}
+	p.Printf(" (%s keys, %s values)",
+		humanize.Bytes.Uint64(s.KeyBytes),
+		humanize.Bytes.Uint64(s.ValueBytes),
+	)
+	if s.SeparatedPointValue.Count != 0 {
+		p.Printf("; separated: %s (%s, %s fetched)",
+			humanize.Count.Uint64(s.SeparatedPointValue.Count),
+			humanize.Bytes.Uint64(s.SeparatedPointValue.ValueBytes),
+			humanize.Bytes.Uint64(s.SeparatedPointValue.ValueBytesFetched))
+	}
+}
diff --git a/iterator.go b/iterator.go
index 2eee5b27..f19df53e 100644
--- a/iterator.go
+++ b/iterator.go
@@ -154,6 +154,18 @@ func (s *RangeKeyIteratorStats) Merge(o RangeKeyIteratorStats) {
 	s.SkippedPoints += o.SkippedPoints
 }
 
+func (s *RangeKeyIteratorStats) String() string {
+	return redact.StringWithoutMarkers(s)
+}
+
+// SafeFormat implements the redact.SafeFormatter interface.
+func (s *RangeKeyIteratorStats) SafeFormat(p redact.SafePrinter, verb rune) {
+	p.Printf("range keys: %s, contained points: %s (%s skipped)",
+		humanize.Count.Uint64(uint64(s.Count)),
+		humanize.Count.Uint64(uint64(s.ContainedPoints)),
+		humanize.Count.Uint64(uint64(s.SkippedPoints)))
+}
+
 // LazyValue is a lazy value. See the long comment in base.LazyValue.
 type LazyValue = base.LazyValue
 
@@ -2788,44 +2800,44 @@ func (stats *IteratorStats) String() string {
 
 // SafeFormat implements the redact.SafeFormatter interface.
 func (stats *IteratorStats) SafeFormat(s redact.SafePrinter, verb rune) {
-	for i := range stats.ForwardStepCount {
-		switch IteratorStatsKind(i) {
-		case InterfaceCall:
-			s.SafeString("(interface (dir, seek, step): ")
-		case InternalIterCall:
-			s.SafeString(", (internal (dir, seek, step): ")
-		}
-		s.Printf("(fwd, %d, %d), (rev, %d, %d))",
-			redact.Safe(stats.ForwardSeekCount[i]), redact.Safe(stats.ForwardStepCount[i]),
-			redact.Safe(stats.ReverseSeekCount[i]), redact.Safe(stats.ReverseStepCount[i]))
+	if stats.ReverseSeekCount[InterfaceCall] == 0 && stats.ReverseSeekCount[InternalIterCall] == 0 {
+		s.Printf("seeked %s times (%s internal)",
+			humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InternalIterCall])),
+		)
+	} else {
+		s.Printf("seeked %s times (%s fwd/%s rev, internal: %s fwd/%s rev)",
+			humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InterfaceCall]+stats.ReverseSeekCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ReverseSeekCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InternalIterCall])),
+			humanize.Count.Uint64(uint64(stats.ReverseSeekCount[InternalIterCall])),
+		)
 	}
-	if stats.InternalStats != (InternalIteratorStats{}) {
-		s.SafeString(",\n(internal-stats: ")
-		s.Printf("(block-bytes: (total %s, cached %s, read-time %s)), "+
-			"(points: (count %s, key-bytes %s, value-bytes %s, tombstoned %s))",
-			humanize.Bytes.Uint64(stats.InternalStats.BlockBytes),
-			humanize.Bytes.Uint64(stats.InternalStats.BlockBytesInCache),
-			humanize.FormattedString(stats.InternalStats.BlockReadDuration.String()),
-			humanize.Count.Uint64(stats.InternalStats.PointCount),
-			humanize.Bytes.Uint64(stats.InternalStats.KeyBytes),
-			humanize.Bytes.Uint64(stats.InternalStats.ValueBytes),
-			humanize.Count.Uint64(stats.InternalStats.PointsCoveredByRangeTombstones),
+	s.SafeString("; ")
+
+	if stats.ReverseStepCount[InterfaceCall] == 0 && stats.ReverseStepCount[InternalIterCall] == 0 {
+		s.Printf("stepped %s times (%s internal)",
+			humanize.Count.Uint64(uint64(stats.ForwardStepCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ForwardStepCount[InternalIterCall])),
 		)
-		if stats.InternalStats.SeparatedPointValue.Count != 0 {
-			s.Printf(", (separated: (count %s, bytes %s, fetched %s)))",
-				humanize.Count.Uint64(stats.InternalStats.SeparatedPointValue.Count),
-				humanize.Bytes.Uint64(stats.InternalStats.SeparatedPointValue.ValueBytes),
-				humanize.Bytes.Uint64(stats.InternalStats.SeparatedPointValue.ValueBytesFetched))
-		} else {
-			s.Printf(")")
-		}
+	} else {
+		s.Printf("stepped %s times (%s fwd/%s rev, internal: %s fwd/%s rev)",
+			humanize.Count.Uint64(uint64(stats.ForwardStepCount[InterfaceCall]+stats.ReverseStepCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ForwardStepCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ReverseStepCount[InterfaceCall])),
+			humanize.Count.Uint64(uint64(stats.ForwardStepCount[InternalIterCall])),
+			humanize.Count.Uint64(uint64(stats.ReverseStepCount[InternalIterCall])),
+		)
+	}
+
+	if stats.InternalStats != (InternalIteratorStats{}) {
+		s.SafeString("; ")
+		stats.InternalStats.SafeFormat(s, verb)
 	}
 	if stats.RangeKeyStats != (RangeKeyIteratorStats{}) {
-		s.SafeString(",\n(range-key-stats: ")
-		s.Printf("(count %d), (contained points: (count %d, skipped %d)))",
-			stats.RangeKeyStats.Count,
-			stats.RangeKeyStats.ContainedPoints,
-			stats.RangeKeyStats.SkippedPoints)
+		s.SafeString(", ")
+		stats.RangeKeyStats.SafeFormat(s, verb)
 	}
 }
 


Test patch:
diff --git a/testdata/external_iterator b/testdata/external_iterator
index 589b950f..7d8bafd0 100644
--- a/testdata/external_iterator
+++ b/testdata/external_iterator
@@ -253,8 +253,7 @@ aaaa@3: (aaaa@3, .)
 aaaa@1: (aaaa@1, .)
 aaaaa@3: (aaaaa@3, .)
 aaaaa@1: (aaaaa@1, .)
-stats: (interface (dir, seek, step): (fwd, 5, 5), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 5, 5), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 475B, cached 0B, read-time 0s)), (points: (count 10, key-bytes 50B, value-bytes 50B, tombstoned 0)))
+stats: seeked 5 times (5 internal); stepped 5 times (5 internal); blocks: 0B cached, 475B not cached (read time: 0s); points: 10 (50B keys, 50B values)
 
 # Note the inclusion of fwd-only. This iterator will use the TrySeekUsingNext
 # optimization and loads ~half the block-bytes as a result.
@@ -282,5 +281,4 @@ aaaa@3: (aaaa@3, .)
 aaaa@1: (aaaa@1, .)
 aaaaa@3: (aaaaa@3, .)
 aaaaa@1: (aaaaa@1, .)
-stats: (interface (dir, seek, step): (fwd, 5, 5), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 5, 5), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 281B, cached 0B, read-time 0s)), (points: (count 10, key-bytes 50B, value-bytes 50B, tombstoned 0)))
+stats: seeked 5 times (5 internal); stepped 5 times (5 internal); blocks: 0B cached, 281B not cached (read time: 0s); points: 10 (50B keys, 50B values)
diff --git a/testdata/iter_histories/iter_optimizations b/testdata/iter_histories/iter_optimizations
index 33a79697..789622f9 100644
--- a/testdata/iter_histories/iter_optimizations
+++ b/testdata/iter_histories/iter_optimizations
@@ -199,8 +199,7 @@ stats
 ----
 lastPositioningOp="unknown"
 b@5: (b@5, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 119B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached, 119B not cached (read time: 0s); points: 1 (3B keys, 3B values)
 
 mutate batch=foo
 set h@2 h@2
@@ -215,8 +214,7 @@ stats
 .
 lastPositioningOp="seekprefixge"
 c@3: (c@3, .)
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 119B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 6B, value-bytes 6B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 0 times (0 internal); blocks: 0B cached, 119B not cached (read time: 0s); points: 2 (6B keys, 6B values)
 
 mutate batch=foo
 set i@1 i@1
@@ -231,8 +229,7 @@ stats
 .
 lastPositioningOp="seekprefixge"
 d@9: (d@9, .)
-stats: (interface (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 119B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 9B, value-bytes 9B, tombstoned 0)))
+stats: seeked 3 times (3 internal); stepped 0 times (0 internal); blocks: 0B cached, 119B not cached (read time: 0s); points: 3 (9B keys, 9B values)
 
 mutate batch=foo
 set j@6 j@6
@@ -247,8 +244,7 @@ stats
 .
 lastPositioningOp="seekprefixge"
 e@8: (e@8, .)
-stats: (interface (dir, seek, step): (fwd, 4, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 4, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 119B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 12B, value-bytes 12B, tombstoned 0)))
+stats: seeked 4 times (4 internal); stepped 0 times (0 internal); blocks: 0B cached, 119B not cached (read time: 0s); points: 4 (12B keys, 12B values)
 
 # Ensure that a case eligible for TrySeekUsingNext across a SetOptions correctly
 # sees new batch mutations. The batch iterator should ignore the
diff --git a/testdata/iter_histories/range_key_masking b/testdata/iter_histories/range_key_masking
index f13c71ae..2252c46a 100644
--- a/testdata/iter_histories/range_key_masking
+++ b/testdata/iter_histories/range_key_masking
@@ -153,9 +153,7 @@ stats
 ----
 a: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 1.1KB, cached 0B, read-time 0s)), (points: (count 25, key-bytes 75B, value-bytes 75B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 25, skipped 25)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached, 1.1KB not cached (read time: 0s); points: 25 (75B keys, 75B values), range keys: 1, contained points: 25 (25 skipped)
 
 # Repeat the above test, but with an iterator that uses a block-property filter
 # mask. The internal stats should reflect fewer bytes read and fewer points
@@ -168,9 +166,7 @@ stats
 ----
 a: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 514B, cached 514B, read-time 0s)), (points: (count 2, key-bytes 6B, value-bytes 6B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 2, skipped 2)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 514B cached; points: 2 (6B keys, 6B values), range keys: 1, contained points: 2 (2 skipped)
 
 # Perform a similar comparison in reverse.
 
@@ -181,9 +177,7 @@ stats
 ----
 a: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 1.1KB, cached 1.1KB, read-time 0s)), (points: (count 25, key-bytes 75B, value-bytes 75B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 25, skipped 25)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 1.1KB cached; points: 25 (75B keys, 75B values), range keys: 1, contained points: 25 (25 skipped)
 
 combined-iter mask-suffix=@9 mask-filter
 last
@@ -192,9 +186,7 @@ stats
 ----
 a: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 514B, cached 514B, read-time 0s)), (points: (count 2, key-bytes 6B, value-bytes 6B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 2, skipped 2)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 514B cached; points: 2 (6B keys, 6B values), range keys: 1, contained points: 2 (2 skipped)
 
 # Perform similar comparisons with seeks.
 
@@ -205,9 +197,7 @@ stats
 ----
 m: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 789B, cached 789B, read-time 0s)), (points: (count 13, key-bytes 39B, value-bytes 39B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 13, skipped 13)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 789B cached; points: 13 (39B keys, 39B values), range keys: 1, contained points: 13 (13 skipped)
 
 combined-iter mask-suffix=@9 mask-filter
 seek-ge m
@@ -216,9 +206,7 @@ stats
 ----
 m: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 514B, cached 514B, read-time 0s)), (points: (count 2, key-bytes 6B, value-bytes 6B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 2, skipped 2)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 514B cached; points: 2 (6B keys, 6B values), range keys: 1, contained points: 2 (2 skipped)
 
 combined-iter mask-suffix=@9
 seek-lt m
@@ -227,9 +215,7 @@ stats
 ----
 a: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 789B, cached 789B, read-time 0s)), (points: (count 12, key-bytes 36B, value-bytes 36B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 12, skipped 12)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 789B cached; points: 12 (36B keys, 36B values), range keys: 1, contained points: 12 (12 skipped)
 
 combined-iter mask-suffix=@9 mask-filter
 seek-lt m
@@ -238,6 +224,4 @@ stats
 ----
 a: (., [a-z) @5=boop UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 539B, cached 539B, read-time 0s)), (points: (count 2, key-bytes 6B, value-bytes 6B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 2, skipped 2)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 539B cached; points: 2 (6B keys, 6B values), range keys: 1, contained points: 2 (2 skipped)
diff --git a/testdata/iter_histories/stats_no_invariants b/testdata/iter_histories/stats_no_invariants
index fb64b720..ac1cf0de 100644
--- a/testdata/iter_histories/stats_no_invariants
+++ b/testdata/iter_histories/stats_no_invariants
@@ -30,19 +30,15 @@ next
 next
 stats
 ----
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 0, 0))
+stats: seeked 0 times (0 internal); stepped 0 times (0 internal)
 a: (a, .)
 b: (b, [b-c) @5=boop UPDATED)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 89B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0))),
-(range-key-stats: (count 1), (contained points: (count 1, skipped 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached, 89B not cached (read time: 0s); points: 2 (2B keys, 2B values), range keys: 1, contained points: 1 (0 skipped)
 c: (c, . UPDATED)
 cat: (., [cat-dog) @3=beep UPDATED)
 d: (d, [cat-dog) @3=beep)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 5), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 6), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 89B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0))),
-(range-key-stats: (count 2), (contained points: (count 2, skipped 0)))
+stats: seeked 1 times (1 internal); stepped 5 times (6 internal); blocks: 0B cached, 89B not cached (read time: 0s); points: 4 (4B keys, 4B values), range keys: 2, contained points: 2 (0 skipped)
 
 # Do the above forward iteration but with a mask suffix. The results should be
 # identical despite range keys serving as masks, because none of the point keys
@@ -63,9 +59,7 @@ c: (c, . UPDATED)
 cat: (., [cat-dog) @3=beep UPDATED)
 d: (d, [cat-dog) @3=beep)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 5), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 6), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 89B, cached 89B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0))),
-(range-key-stats: (count 2), (contained points: (count 2, skipped 0)))
+stats: seeked 1 times (1 internal); stepped 5 times (6 internal); blocks: 89B cached; points: 4 (4B keys, 4B values), range keys: 2, contained points: 2 (0 skipped)
 
 # Scan backward
 
@@ -84,9 +78,7 @@ c: (c, . UPDATED)
 b: (b, [b-c) @5=boop UPDATED)
 a: (a, . UPDATED)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 5)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 6)),
-(internal-stats: (block-bytes: (total 89B, cached 89B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0))),
-(range-key-stats: (count 2), (contained points: (count 2, skipped 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 5 times (0 fwd/5 rev, internal: 0 fwd/6 rev); blocks: 89B cached; points: 4 (4B keys, 4B values), range keys: 2, contained points: 2 (0 skipped)
 
 combined-iter
 seek-ge ace
@@ -107,9 +99,7 @@ cat: (., [cat-dog) @3=beep)
 d: (d, [cat-dog) @3=beep)
 day: (., [cat-dog) @3=beep)
 .
-stats: (interface (dir, seek, step): (fwd, 8, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 6, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 89B, cached 89B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0))),
-(range-key-stats: (count 2), (contained points: (count 3, skipped 0)))
+stats: seeked 8 times (6 internal); stepped 0 times (4 internal); blocks: 89B cached; points: 4 (4B keys, 4B values), range keys: 2, contained points: 3 (0 skipped)
 
 combined-iter
 seek-lt 1
@@ -134,9 +124,7 @@ cat: (., [cat-dog) @3=beep UPDATED)
 d: (d, [cat-dog) @3=beep)
 d: (d, [cat-dog) @3=beep)
 d: (d, [cat-dog) @3=beep)
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 10, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 10, 10)),
-(internal-stats: (block-bytes: (total 267B, cached 267B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0))),
-(range-key-stats: (count 2), (contained points: (count 6, skipped 0)))
+stats: seeked 10 times (0 fwd/10 rev, internal: 0 fwd/10 rev); stepped 0 times (0 fwd/0 rev, internal: 0 fwd/10 rev); blocks: 267B cached; points: 15 (15B keys, 15B values), range keys: 2, contained points: 6 (0 skipped)
 
 rangekey-iter
 first
@@ -155,5 +143,4 @@ cat [cat-dog) @3=beep UPDATED
 bat [bat-c) @5=boop UPDATED
 cat [cat-catatonic) @3=beep UPDATED
 .
-stats: (interface (dir, seek, step): (fwd, 2, 4), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 4), (rev, 0, 0)),
-(range-key-stats: (count 4), (contained points: (count 0, skipped 0)))
+stats: seeked 2 times (2 internal); stepped 4 times (4 internal), range keys: 4, contained points: 0 (0 skipped)
diff --git a/testdata/iterator b/testdata/iterator
index cad4f0d2..5033190a 100644
--- a/testdata/iterator
+++ b/testdata/iterator
@@ -10,20 +10,19 @@ prev
 a: (b, .)
 .
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 seek-ge b
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal)
 
 iter seq=2
 seek-lt a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 0))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 0 times (0 internal)
 
 
 define
@@ -39,8 +38,7 @@ prev
 a: (b, .)
 .
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/1 rev); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=3
 seek-ge a
@@ -50,8 +48,7 @@ prev
 a: (c, .)
 .
 a: (c, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 1, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 2 fwd/2 rev); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -63,8 +60,7 @@ a: (b, .)
 .
 err=pebble: unsupported reverse prefix iteration
 err=pebble: unsupported reverse prefix iteration
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 3 times (2 fwd/1 rev, internal: 1 fwd/0 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=3
 seek-prefix-ge a
@@ -72,8 +68,7 @@ next
 ----
 a: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 
 define
@@ -85,8 +80,7 @@ iter seq=3
 seek-ge a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 iter seq=2
 seek-ge 1
@@ -94,15 +88,13 @@ next
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 iter seq=3
 seek-lt b
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 0 times (0 fwd/0 rev, internal: 0 fwd/2 rev); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 iter seq=2
 seek-lt b
@@ -112,22 +104,19 @@ next
 a: (b, .)
 .
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 4 (4B keys, 2B values)
 
 iter seq=3
 seek-prefix-ge a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 iter seq=2
 seek-prefix-ge 1
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 0B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 0B values)
 
 define
 a.DEL.2:
@@ -141,43 +130,37 @@ next
 ----
 b: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (3 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 iter seq=3
 seek-ge a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 iter seq=2
 seek-ge a
 ----
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 iter seq=4
 seek-prefix-ge a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 iter seq=3
 seek-prefix-ge a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 iter seq=2
 seek-prefix-ge a
 ----
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -185,8 +168,7 @@ seek-prefix-ge b
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 define
 a.DEL.3:
@@ -204,8 +186,7 @@ seek-prefix-ge c
 .
 .
 c: (d, .)
-stats: (interface (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 3, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 7, key-bytes 7B, value-bytes 4B, tombstoned 0)))
+stats: seeked 3 times (3 internal); stepped 0 times (4 internal); blocks: 0B cached; points: 7 (7B keys, 4B values)
 
 iter seq=3
 seek-prefix-ge a
@@ -215,8 +196,7 @@ seek-prefix-ge c
 a: (b, .)
 b: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 3B, tombstoned 0)))
+stats: seeked 3 times (3 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 5 (5B keys, 3B values)
 
 iter seq=3
 seek-ge a
@@ -226,8 +206,7 @@ seek-ge c
 a: (b, .)
 b: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 3B, tombstoned 0)))
+stats: seeked 3 times (3 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 5 (5B keys, 3B values)
 
 define
 a.SET.1:a
@@ -245,8 +224,7 @@ a: (a, .)
 b: (b, .)
 c: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 3 times (3 internal); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 iter seq=4
 seek-ge b
@@ -254,21 +232,19 @@ next
 ----
 b: (b, .)
 c: (c, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=4
 seek-ge c
 ----
 c: (c, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=4
 seek-lt a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 0))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 0 times (0 internal)
 
 iter seq=4
 seek-lt b
@@ -278,8 +254,7 @@ next
 a: (a, .)
 .
 a: (a, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=4
 seek-lt c
@@ -291,8 +266,7 @@ b: (b, .)
 a: (a, .)
 .
 a: (a, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 2)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 3 times (1 fwd/2 rev, internal: 0 fwd/2 rev); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 
 iter seq=4
@@ -307,8 +281,7 @@ b: (b, .)
 a: (a, .)
 .
 a: (a, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 3)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 3)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 4 times (1 fwd/3 rev, internal: 0 fwd/3 rev); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=4
 seek-prefix-ge a
@@ -316,8 +289,7 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=4
 seek-prefix-ge b
@@ -325,8 +297,7 @@ next
 ----
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 
 iter seq=4
@@ -335,15 +306,14 @@ next
 ----
 c: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 
 iter seq=4
 seek-prefix-ge d
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal)
 
 iter seq=4
 seek-prefix-ge a
@@ -353,8 +323,7 @@ seek-prefix-ge b
 a: (a, .)
 c: (c, .)
 b: (b, .)
-stats: (interface (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 3 times (3 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 define
 a.SET.b2:b
@@ -369,21 +338,19 @@ prev
 a: (b, .)
 .
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/1 rev); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=2
 seek-ge b
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 seek-lt a
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 0))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 0 times (0 internal)
 
 iter seq=2
 seek-lt b
@@ -393,8 +360,7 @@ next
 a: (b, .)
 .
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 seek-lt c
@@ -404,8 +370,7 @@ next
 a: (b, .)
 .
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 2 times (1 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -413,15 +378,13 @@ next
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 seek-prefix-ge b
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 
 define
@@ -437,8 +400,7 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (3B keys, 3B values)
 
 iter seq=5
 seek-prefix-ge a
@@ -446,15 +408,13 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (3B keys, 3B values)
 
 iter seq=5
 seek-prefix-ge aa
 ----
 aa: (aa, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (2B keys, 2B values)
 
 iter seq=5
 seek-prefix-ge aa
@@ -462,8 +422,7 @@ next
 ----
 aa: (aa, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (5B keys, 5B values)
 
 iter seq=5
 seek-prefix-ge aa
@@ -471,8 +430,7 @@ next
 ----
 aa: (aa, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (5B keys, 5B values)
 
 iter seq=5
 seek-prefix-ge aaa
@@ -480,15 +438,13 @@ next
 ----
 aaa: (aaa, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (4B keys, 4B values)
 
 iter seq=5
 seek-prefix-ge aaa
 ----
 aaa: (aaa, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (3B keys, 3B values)
 
 iter seq=5
 seek-prefix-ge b
@@ -496,8 +452,7 @@ next
 ----
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=5
 seek-prefix-ge aa
@@ -513,8 +468,7 @@ aaa: (aaa, .)
 aa: (aa, .)
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 1, 4)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 4)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 9B, value-bytes 9B, tombstoned 0)))
+stats: seeked 2 times (1 fwd/1 rev, internal: 1 fwd/1 rev); stepped 4 times (0 fwd/4 rev, internal: 0 fwd/4 rev); blocks: 0B cached; points: 5 (9B keys, 9B values)
 
 iter seq=5
 seek-prefix-ge aa
@@ -530,8 +484,7 @@ aa: (aa, .)
 aaa: (aaa, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 4), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 9B, value-bytes 9B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 4 times (4 internal); blocks: 0B cached; points: 5 (9B keys, 9B values)
 
 iter seq=5
 seek-prefix-ge aaa
@@ -545,8 +498,7 @@ aa: (aa, .)
 aaa: (aaa, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 3), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 9B, value-bytes 9B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 3 times (3 internal); blocks: 0B cached; points: 4 (9B keys, 9B values)
 
 iter seq=5
 seek-prefix-ge aaa
@@ -558,8 +510,7 @@ aaa: (aaa, .)
 aaa: (aaa, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 7B, value-bytes 7B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 2 times (2 internal); blocks: 0B cached; points: 3 (7B keys, 7B values)
 
 iter seq=5
 seek-prefix-ge aaa
@@ -575,8 +526,7 @@ aa: (aa, .)
 aaa: (aaa, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 4), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 2, 4), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 6, key-bytes 11B, value-bytes 11B, tombstoned 0)))
+stats: seeked 2 times (1 fwd/1 rev, internal: 2 fwd/1 rev); stepped 4 times (4 fwd/0 rev, internal: 4 fwd/1 rev); blocks: 0B cached; points: 6 (11B keys, 11B values)
 
 
 iter seq=5
@@ -589,8 +539,7 @@ aaa: (aaa, .)
 aaa: (aaa, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 12B, value-bytes 12B, tombstoned 0)))
+stats: seeked 2 times (1 fwd/1 rev, internal: 1 fwd/1 rev); stepped 2 times (2 fwd/0 rev, internal: 3 fwd/1 rev); blocks: 0B cached; points: 5 (12B keys, 12B values)
 
 iter seq=4
 seek-prefix-ge a
@@ -602,8 +551,7 @@ a: (a, .)
 aa: (aa, .)
 aaa: (aaa, .)
 .
-stats: (interface (dir, seek, step): (fwd, 4, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 4, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 7B, value-bytes 7B, tombstoned 0)))
+stats: seeked 4 times (4 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 4 (7B keys, 7B values)
 
 iter seq=3
 seek-prefix-ge aaa
@@ -617,8 +565,7 @@ seek-prefix-ge aaa
 a: (a, .)
 aa: (aa, .)
 .
-stats: (interface (dir, seek, step): (fwd, 5, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 5, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 7, key-bytes 12B, value-bytes 12B, tombstoned 0)))
+stats: seeked 5 times (5 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 7 (12B keys, 12B values)
 
 define
 bb.DEL.2:
@@ -630,8 +577,7 @@ iter seq=4
 seek-prefix-ge bb
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 7B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 3 (7B keys, 2B values)
 
 
 define
@@ -652,8 +598,7 @@ a: (bcd, .)
 b: (ab, .)
 .
 b: (ab, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 5), (rev, 1, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 8, key-bytes 8B, value-bytes 8B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 3 times (2 fwd/1 rev, internal: 5 fwd/2 rev); blocks: 0B cached; points: 8 (8B keys, 8B values)
 
 iter seq=3
 seek-ge a
@@ -661,8 +606,7 @@ next
 ----
 a: (bc, .)
 b: (ab, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (4 internal); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=2
 seek-ge a
@@ -670,8 +614,7 @@ next
 ----
 a: (b, .)
 b: (a, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=4
 seek-lt c
@@ -683,8 +626,7 @@ b: (ab, .)
 a: (bcd, .)
 .
 a: (bcd, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 2)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 1, 5)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 8, key-bytes 8B, value-bytes 8B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 3 times (1 fwd/2 rev, internal: 2 fwd/5 rev); blocks: 0B cached; points: 8 (8B keys, 8B values)
 
 iter seq=3
 seek-lt c
@@ -692,8 +634,7 @@ prev
 ----
 b: (ab, .)
 a: (bc, .)
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 4)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/4 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=2
 seek-lt c
@@ -701,8 +642,7 @@ prev
 ----
 b: (a, .)
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/2 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=4
 seek-ge a
@@ -714,8 +654,7 @@ a: (bcd, .)
 b: (ab, .)
 a: (bcd, .)
 b: (ab, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 10), (rev, 1, 5)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 2 fwd/1 rev); stepped 3 times (2 fwd/1 rev, internal: 10 fwd/5 rev); blocks: 0B cached; points: 15 (15B keys, 15B values)
 
 iter seq=3
 seek-ge a
@@ -727,8 +666,7 @@ a: (bc, .)
 b: (ab, .)
 a: (bc, .)
 b: (ab, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 8), (rev, 1, 4)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 2 fwd/1 rev); stepped 3 times (2 fwd/1 rev, internal: 8 fwd/4 rev); blocks: 0B cached; points: 15 (15B keys, 15B values)
 
 iter seq=2
 seek-ge a
@@ -740,8 +678,7 @@ a: (b, .)
 b: (a, .)
 a: (b, .)
 b: (a, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 4), (rev, 1, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 2 fwd/1 rev); stepped 3 times (2 fwd/1 rev, internal: 4 fwd/2 rev); blocks: 0B cached; points: 15 (15B keys, 15B values)
 
 iter seq=4
 seek-lt c
@@ -753,8 +690,7 @@ b: (ab, .)
 a: (bcd, .)
 b: (ab, .)
 a: (bcd, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 2)), (internal (dir, seek, step): (fwd, 1, 5), (rev, 2, 10)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/2 rev); stepped 3 times (1 fwd/2 rev, internal: 5 fwd/10 rev); blocks: 0B cached; points: 15 (15B keys, 15B values)
 
 iter seq=3
 seek-lt c
@@ -766,8 +702,7 @@ b: (ab, .)
 a: (bc, .)
 b: (ab, .)
 a: (bc, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 2)), (internal (dir, seek, step): (fwd, 1, 4), (rev, 2, 8)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/2 rev); stepped 3 times (1 fwd/2 rev, internal: 4 fwd/8 rev); blocks: 0B cached; points: 15 (15B keys, 15B values)
 
 iter seq=2
 seek-lt c
@@ -779,8 +714,7 @@ b: (a, .)
 a: (b, .)
 b: (a, .)
 a: (b, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 2)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 2, 4)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 15B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/2 rev); stepped 3 times (1 fwd/2 rev, internal: 2 fwd/4 rev); blocks: 0B cached; points: 15 (15B keys, 15B values)
 
 iter seq=3
 seek-prefix-ge a
@@ -788,8 +722,7 @@ next
 ----
 a: (bc, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -797,8 +730,7 @@ next
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=4
 seek-prefix-ge a
@@ -806,8 +738,7 @@ next
 ----
 a: (bcd, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (3 internal); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -815,8 +746,7 @@ next
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=3
 seek-prefix-ge a
@@ -824,28 +754,25 @@ next
 ----
 a: (bc, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=3
 seek-prefix-ge c
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal)
 
 iter seq=3
 seek-prefix-ge 1
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=3
 seek-prefix-ge a
 ----
 a: (bc, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (1 internal); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 
 define
@@ -866,8 +793,7 @@ next
 a: (bc, .)
 .
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 5B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 2 times (2 internal); blocks: 0B cached; points: 4 (5B keys, 4B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -877,8 +803,7 @@ next
 a: (b, .)
 .
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 5B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 2 times (1 internal); blocks: 0B cached; points: 4 (5B keys, 4B values)
 
 iter seq=4
 seek-prefix-ge a
@@ -886,8 +811,7 @@ next
 ----
 a: (bcd, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 5B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (3 internal); blocks: 0B cached; points: 4 (5B keys, 4B values)
 
 iter seq=2
 seek-prefix-ge a
@@ -895,8 +819,7 @@ next
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 5B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 4 (5B keys, 4B values)
 
 iter seq=3
 seek-prefix-ge aa
@@ -904,15 +827,13 @@ next
 ----
 aa: (ab, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 5B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached; points: 3 (5B keys, 3B values)
 
 iter seq=4
 seek-prefix-ge aa
 ----
 aa: (ab, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 5B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 3 (5B keys, 3B values)
 
 define
 a.SET.1:a
@@ -929,8 +850,7 @@ prev
 a: (a, .)
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2 lower=b
 seek-ge a
@@ -940,8 +860,7 @@ prev
 b: (b, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2 lower=c
 seek-ge a
@@ -951,8 +870,7 @@ prev
 c: (c, .)
 c: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2 lower=d
 seek-ge a
@@ -962,8 +880,7 @@ prev
 d: (d, .)
 d: (d, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2 lower=e
 seek-ge a
@@ -971,7 +888,7 @@ first
 ----
 .
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 0))
+stats: seeked 2 times (2 internal); stepped 0 times (0 internal)
 
 iter seq=2 upper=d
 seek-lt d
@@ -981,8 +898,7 @@ next
 c: (c, .)
 c: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 0, 2), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 2 times (0 fwd/2 rev, internal: 0 fwd/2 rev); stepped 1 times (1 fwd/0 rev, internal: 2 fwd/2 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=2 upper=c
 seek-lt d
@@ -992,8 +908,7 @@ next
 b: (b, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 0, 2), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 2 times (0 fwd/2 rev, internal: 0 fwd/2 rev); stepped 1 times (1 fwd/0 rev, internal: 2 fwd/2 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=2 upper=b
 seek-lt d
@@ -1003,8 +918,7 @@ next
 a: (a, .)
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 2 times (0 fwd/2 rev, internal: 1 fwd/2 rev); stepped 1 times (1 fwd/0 rev, internal: 1 fwd/2 rev); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 iter seq=2 upper=a
 seek-lt d
@@ -1012,7 +926,7 @@ last
 ----
 .
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 2, 0))
+stats: seeked 2 times (0 fwd/2 rev, internal: 0 fwd/2 rev); stepped 0 times (0 internal)
 
 iter seq=2 lower=b upper=c
 seek-ge a
@@ -1020,8 +934,7 @@ next
 ----
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 set-bounds lower=a
@@ -1033,8 +946,7 @@ prev
 a: (a, .)
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 set-bounds lower=b
@@ -1046,8 +958,7 @@ prev
 b: (b, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 set-bounds lower=c
@@ -1059,8 +970,7 @@ prev
 c: (c, .)
 c: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 set-bounds lower=d
@@ -1072,8 +982,7 @@ prev
 d: (d, .)
 d: (d, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 set-bounds lower=e
@@ -1083,7 +992,7 @@ first
 .
 .
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 0))
+stats: seeked 2 times (2 internal); stepped 0 times (0 internal)
 
 iter seq=2
 set-bounds upper=d
@@ -1095,8 +1004,7 @@ next
 c: (c, .)
 c: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 0, 2), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 2 times (0 fwd/2 rev, internal: 0 fwd/2 rev); stepped 1 times (1 fwd/0 rev, internal: 2 fwd/2 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=2
 set-bounds upper=c
@@ -1108,8 +1016,7 @@ next
 b: (b, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 0, 2), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 2 times (0 fwd/2 rev, internal: 0 fwd/2 rev); stepped 1 times (1 fwd/0 rev, internal: 2 fwd/2 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 iter seq=2
 set-bounds upper=b
@@ -1121,8 +1028,7 @@ next
 a: (a, .)
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 2 times (0 fwd/2 rev, internal: 1 fwd/2 rev); stepped 1 times (1 fwd/0 rev, internal: 1 fwd/2 rev); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 iter seq=2
 set-bounds upper=a
@@ -1132,7 +1038,7 @@ last
 .
 .
 .
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 2, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 2, 0))
+stats: seeked 2 times (0 fwd/2 rev, internal: 0 fwd/2 rev); stepped 0 times (0 internal)
 
 iter seq=2
 set-bounds lower=a
@@ -1144,8 +1050,7 @@ next
 c: (c, .)
 d: (d, .)
 .
-stats: (interface (dir, seek, step): (fwd, 0, 2), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 3), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 2 times (2 fwd/0 rev, internal: 3 fwd/1 rev); blocks: 0B cached; points: 4 (4B keys, 4B values)
 
 iter seq=2
 set-bounds lower=b upper=c
@@ -1155,8 +1060,7 @@ next
 .
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 set-bounds lower=b
@@ -1168,8 +1072,7 @@ seek-ge a
 b: (b, .)
 .
 b: (b, .)
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 seek-ge a
@@ -1177,8 +1080,7 @@ set-bounds upper=e
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 set-bounds lower=b
@@ -1188,8 +1090,7 @@ set-bounds upper=e
 .
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 set-bounds lower=b
@@ -1197,8 +1098,7 @@ first
 ----
 .
 b: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 set-bounds upper=b
@@ -1206,8 +1106,7 @@ first
 ----
 .
 a: (a, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2
 set-bounds lower=b
@@ -1215,8 +1114,7 @@ last
 ----
 .
 d: (d, .)
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 0 times (0 fwd/0 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 set-bounds upper=b
@@ -1224,8 +1122,7 @@ last
 ----
 .
 a: (a, .)
-stats: (interface (dir, seek, step): (fwd, 0, 0), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); stepped 0 times (0 fwd/0 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 # The prev call after "set-bounds upper=c" will assume that the iterator
 # is exhausted due to having stepped up to c. Which means prev should step
@@ -1240,8 +1137,7 @@ d: (d, .)
 .
 .
 b: (b, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 1)), (internal (dir, seek, step): (fwd, 0, 2), (rev, 2, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 5, key-bytes 5B, value-bytes 5B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 0 fwd/2 rev); stepped 2 times (1 fwd/1 rev, internal: 2 fwd/2 rev); blocks: 0B cached; points: 5 (5B keys, 5B values)
 
 # The next call after "set-bounds lower=b" will assume that the iterator
 # is exhausted due to having stepped below b. Which means next should step
@@ -1256,8 +1152,7 @@ a: (a, .)
 .
 .
 b: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (2 internal); stepped 2 times (1 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 iter seq=2
 set-bounds lower=b
@@ -1267,8 +1162,7 @@ next
 .
 b: (b, .)
 c: (c, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 1, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 iter seq=2
 set-bounds upper=d
@@ -1278,8 +1172,7 @@ prev
 .
 c: (c, .)
 b: (b, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 2)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/2 rev); blocks: 0B cached; points: 3 (3B keys, 3B values)
 
 define
 a.SET.1:a
@@ -1296,15 +1189,14 @@ prev
 a: (a, .)
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 1)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 2 times (2 internal); stepped 1 times (0 fwd/1 rev, internal: 0 fwd/1 rev); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 
 iter seq=2 lower=aa
 seek-prefix-ge a
 ----
 err=pebble: SeekPrefixGE supplied with key outside of lower bound
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 0, 0), (rev, 0, 0))
+stats: seeked 1 times (0 internal); stepped 0 times (0 internal)
 
 iter seq=2 lower=a upper=aa
 seek-prefix-ge a
@@ -1312,8 +1204,7 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 1 (1B keys, 1B values)
 
 iter seq=2 lower=a upper=aaa
 seek-prefix-ge a
@@ -1321,8 +1212,7 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (3B keys, 3B values)
 
 iter seq=2 lower=a upper=b
 seek-prefix-ge a
@@ -1330,8 +1220,7 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (3B keys, 3B values)
 
 iter seq=2 lower=a upper=c
 seek-prefix-ge a
@@ -1339,15 +1228,13 @@ next
 ----
 a: (a, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 3B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 2 (3B keys, 3B values)
 
 iter seq=2 lower=a upper=aaa
 seek-prefix-ge aa
 ----
 aa: (aa, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 1 (2B keys, 2B values)
 
 iter seq=2 lower=a upper=aaa
 seek-prefix-ge aa
@@ -1355,8 +1242,7 @@ next
 ----
 aa: (aa, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (1 internal); blocks: 0B cached; points: 1 (2B keys, 2B values)
 
 define
 a.SET.1:a
@@ -1371,8 +1257,7 @@ next
 a: (a, .)
 b: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 2 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 2B values)
 
 define
 a.SINGLEDEL.1:
@@ -1382,8 +1267,7 @@ iter seq=2
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 0B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (1 internal); blocks: 0B cached; points: 1 (1B keys, 0B values)
 
 define
 a.SINGLEDEL.2:
@@ -1394,8 +1278,7 @@ iter seq=3
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 0B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 0B values)
 
 define
 a.SINGLEDEL.2:
@@ -1406,8 +1289,7 @@ iter seq=3
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 0B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 0B values)
 
 define
 a.SINGLEDEL.2:
@@ -1418,8 +1300,7 @@ iter seq=3
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 0B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 0B values)
 
 define
 a.SINGLEDEL.2:
@@ -1430,8 +1311,7 @@ iter seq=3
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 define
 a.SET.2:b
@@ -1444,8 +1324,7 @@ next
 ----
 a: (b, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 1B values)
 
 define
 a.SINGLEDEL.2:
@@ -1459,8 +1338,7 @@ next
 ----
 b: (c, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 1 times (3 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 define
 a.SINGLEDEL.3:
@@ -1472,8 +1350,7 @@ iter
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 define
 a.SINGLEDEL.3:
@@ -1485,8 +1362,7 @@ iter seq=4
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 3, key-bytes 3B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (3 internal); blocks: 0B cached; points: 3 (3B keys, 2B values)
 
 define
 a.SINGLEDEL.4:
@@ -1499,8 +1375,7 @@ iter seq=5
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 6B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (4 internal); blocks: 0B cached; points: 4 (4B keys, 6B values)
 
 define
 a.SINGLEDEL.4:
@@ -1513,8 +1388,7 @@ iter seq=5
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 6B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (4 internal); blocks: 0B cached; points: 4 (4B keys, 6B values)
 
 define
 a.SINGLEDEL.4:
@@ -1527,8 +1401,7 @@ iter seq=5
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 4, key-bytes 4B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (4 internal); blocks: 0B cached; points: 4 (4B keys, 3B values)
 
 define
 a.SINGLEDEL.3:
@@ -1539,8 +1412,7 @@ iter seq=4
 first
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 3B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (2 internal); blocks: 0B cached; points: 2 (2B keys, 3B values)
 
 # Exercise iteration with limits, when there are no deletes.
 define
@@ -1582,8 +1454,7 @@ a: valid (a, .)
 . exhausted
 . at-limit
 a: valid (a, .)
-stats: (interface (dir, seek, step): (fwd, 1, 6), (rev, 1, 7)), (internal (dir, seek, step): (fwd, 3, 3), (rev, 1, 6)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 11, key-bytes 11B, value-bytes 11B, tombstoned 0)))
+stats: seeked 2 times (1 fwd/1 rev, internal: 3 fwd/1 rev); stepped 13 times (6 fwd/7 rev, internal: 3 fwd/6 rev); blocks: 0B cached; points: 11 (11B keys, 11B values)
 
 # Exercise iteration with limits when we have deletes.
 
@@ -1630,8 +1501,7 @@ d: valid (d, .)
 . exhausted
 d: valid (d, .)
 . exhausted
-stats: (interface (dir, seek, step): (fwd, 1, 10), (rev, 0, 5)), (internal (dir, seek, step): (fwd, 3, 13), (rev, 1, 8)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 21, key-bytes 21B, value-bytes 14B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 3 fwd/1 rev); stepped 15 times (10 fwd/5 rev, internal: 13 fwd/8 rev); blocks: 0B cached; points: 21 (21B keys, 14B values)
 
 iter seq=4
 seek-ge-limit b d
@@ -1643,8 +1513,7 @@ next-limit e
 . at-limit
 . at-limit
 d: valid (d, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 1, 9), (rev, 0, 5)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 15, key-bytes 15B, value-bytes 9B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 3 times (2 fwd/1 rev, internal: 9 fwd/5 rev); blocks: 0B cached; points: 15 (15B keys, 9B values)
 
 iter seq=4
 seek-lt-limit d c
@@ -1660,8 +1529,7 @@ next-limit b
 a: valid (a, .)
 . exhausted
 a: valid (a, .)
-stats: (interface (dir, seek, step): (fwd, 0, 1), (rev, 1, 4)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 1, 5)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 6, key-bytes 6B, value-bytes 4B, tombstoned 0)))
+stats: seeked 1 times (0 fwd/1 rev, internal: 1 fwd/1 rev); stepped 5 times (1 fwd/4 rev, internal: 0 fwd/5 rev); blocks: 0B cached; points: 6 (6B keys, 4B values)
 
 # NB: Zero values are skipped by deletable merger.
 define merger=deletable
@@ -1687,8 +1555,7 @@ prev
 .
 .
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 2)), (internal (dir, seek, step): (fwd, 1, 8), (rev, 1, 8)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 16, key-bytes 16B, value-bytes 24B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 4 times (2 fwd/2 rev, internal: 8 fwd/8 rev); blocks: 0B cached; points: 16 (16B keys, 24B values)
 
 iter seq=4
 seek-ge a
@@ -1702,5 +1569,4 @@ b: (3, .)
 .
 b: (3, .)
 a: (2, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 2)), (internal (dir, seek, step): (fwd, 1, 6), (rev, 1, 6)),
-(internal-stats: (block-bytes: (total 0B, cached 0B, read-time 0s)), (points: (count 16, key-bytes 16B, value-bytes 24B, tombstoned 0)))
+stats: seeked 1 times (1 fwd/0 rev, internal: 1 fwd/1 rev); stepped 4 times (2 fwd/2 rev, internal: 6 fwd/6 rev); blocks: 0B cached; points: 16 (16B keys, 24B values)
diff --git a/testdata/iterator_seek_opt b/testdata/iterator_seek_opt
index 73eda49d..42850569 100644
--- a/testdata/iterator_seek_opt
+++ b/testdata/iterator_seek_opt
@@ -28,7 +28,7 @@ iter
 seek-ge a
 ----
 a: (4, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal)
 SeekGEs with trySeekUsingNext: 0
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -36,7 +36,7 @@ iter
 seek-ge b
 ----
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 2, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 2, 0), (rev, 0, 0))
+stats: seeked 2 times (2 internal); stepped 0 times (0 internal)
 SeekGEs with trySeekUsingNext: 2
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -44,7 +44,7 @@ iter
 seek-ge c
 ----
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 3, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 3, 0), (rev, 0, 0))
+stats: seeked 3 times (3 internal); stepped 0 times (0 internal)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -54,7 +54,7 @@ iter
 seek-ge bb
 ----
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 4, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 4, 0), (rev, 0, 0))
+stats: seeked 4 times (4 internal); stepped 0 times (0 internal)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -65,7 +65,7 @@ iter
 seek-ge bbb
 ----
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 5, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 4, 0), (rev, 0, 0))
+stats: seeked 5 times (4 internal); stepped 0 times (0 internal)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -77,7 +77,7 @@ seek-ge e
 ----
 d: (2, .)
 e: (1, .)
-stats: (interface (dir, seek, step): (fwd, 6, 1), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 5, 1), (rev, 0, 0))
+stats: seeked 6 times (5 internal); stepped 1 times (1 internal)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -87,7 +87,7 @@ seek-ge b
 ----
 d: (2, .)
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 7, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 6, 1), (rev, 0, 3))
+stats: seeked 7 times (6 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -97,7 +97,7 @@ iter
 seek-prefix-ge a
 ----
 a: (4, .)
-stats: (interface (dir, seek, step): (fwd, 8, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 7, 1), (rev, 0, 3))
+stats: seeked 8 times (7 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 0
 
@@ -105,7 +105,7 @@ iter
 seek-prefix-ge b
 ----
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 9, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 8, 1), (rev, 0, 3))
+stats: seeked 9 times (8 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 2
 
@@ -113,7 +113,7 @@ iter
 seek-prefix-ge c
 ----
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 10, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 9, 1), (rev, 0, 3))
+stats: seeked 10 times (9 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -123,7 +123,7 @@ iter
 seek-prefix-ge bb
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 11, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 10, 1), (rev, 0, 3))
+stats: seeked 11 times (10 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -137,7 +137,7 @@ seek-ge a
 ----
 .
 a: (4, .)
-stats: (interface (dir, seek, step): (fwd, 12, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 11, 1), (rev, 0, 3))
+stats: seeked 12 times (11 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -147,7 +147,7 @@ seek-ge b
 ----
 .
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 13, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 12, 1), (rev, 0, 3))
+stats: seeked 13 times (12 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 4
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -155,7 +155,7 @@ iter
 seek-ge bb
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 14, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 13, 1), (rev, 0, 3))
+stats: seeked 14 times (13 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 5
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -165,7 +165,7 @@ seek-ge bbb
 ----
 .
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 15, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 14, 1), (rev, 0, 3))
+stats: seeked 15 times (14 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 5
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -173,7 +173,7 @@ iter
 seek-ge cc
 ----
 .
-stats: (interface (dir, seek, step): (fwd, 16, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 15, 1), (rev, 0, 3))
+stats: seeked 16 times (15 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 6
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -188,7 +188,7 @@ seek-ge b
 ----
 .
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 17, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 16, 1), (rev, 0, 3))
+stats: seeked 17 times (16 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 6
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -198,7 +198,7 @@ seek-ge c
 ----
 .
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 18, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 17, 1), (rev, 0, 3))
+stats: seeked 18 times (17 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 6
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -210,7 +210,7 @@ seek-ge d
 ----
 .
 d: (2, .)
-stats: (interface (dir, seek, step): (fwd, 19, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 18, 1), (rev, 0, 3))
+stats: seeked 19 times (18 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 8
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -220,7 +220,7 @@ seek-prefix-ge b
 ----
 .
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 20, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 19, 1), (rev, 0, 3))
+stats: seeked 20 times (19 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 8
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -230,7 +230,7 @@ seek-prefix-ge c
 ----
 .
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 21, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 20, 1), (rev, 0, 3))
+stats: seeked 21 times (20 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 8
 SeekPrefixGEs with trySeekUsingNext: 4
 
@@ -242,7 +242,7 @@ seek-prefix-ge d
 ----
 .
 d: (2, .)
-stats: (interface (dir, seek, step): (fwd, 22, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 21, 1), (rev, 0, 3))
+stats: seeked 22 times (21 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 8
 SeekPrefixGEs with trySeekUsingNext: 6
 
@@ -258,7 +258,7 @@ seek-ge b
 ----
 .
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 23, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 22, 1), (rev, 0, 3))
+stats: seeked 23 times (22 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 8
 SeekPrefixGEs with trySeekUsingNext: 6
 
@@ -268,7 +268,7 @@ seek-ge c
 ----
 .
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 24, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 23, 1), (rev, 0, 3))
+stats: seeked 24 times (23 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 8
 SeekPrefixGEs with trySeekUsingNext: 6
 
@@ -280,7 +280,7 @@ seek-ge d
 ----
 .
 d: (2, .)
-stats: (interface (dir, seek, step): (fwd, 25, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 24, 1), (rev, 0, 3))
+stats: seeked 25 times (24 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 10
 SeekPrefixGEs with trySeekUsingNext: 6
 
@@ -290,7 +290,7 @@ seek-prefix-ge b
 ----
 .
 b: (1, .)
-stats: (interface (dir, seek, step): (fwd, 26, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 25, 1), (rev, 0, 3))
+stats: seeked 26 times (25 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 10
 SeekPrefixGEs with trySeekUsingNext: 6
 
@@ -300,7 +300,7 @@ seek-prefix-ge c
 ----
 .
 c: (1, .)
-stats: (interface (dir, seek, step): (fwd, 27, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 26, 1), (rev, 0, 3))
+stats: seeked 27 times (26 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 10
 SeekPrefixGEs with trySeekUsingNext: 6
 
@@ -312,6 +312,6 @@ seek-prefix-ge d
 ----
 .
 d: (2, .)
-stats: (interface (dir, seek, step): (fwd, 28, 1), (rev, 0, 1)), (internal (dir, seek, step): (fwd, 27, 1), (rev, 0, 3))
+stats: seeked 28 times (27 internal); stepped 2 times (1 fwd/1 rev, internal: 1 fwd/3 rev)
 SeekGEs with trySeekUsingNext: 10
 SeekPrefixGEs with trySeekUsingNext: 8
diff --git a/testdata/iterator_stats b/testdata/iterator_stats
index c6375b4c..e1c43b6b 100644
--- a/testdata/iterator_stats
+++ b/testdata/iterator_stats
@@ -17,8 +17,7 @@ stats
 a: (1, .)
 c: (2, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 57B, cached 57B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 2 times (2 internal); blocks: 57B cached; points: 2 (2B keys, 2B values)
 
 # Perform the same operation again with a new iterator. It should yield
 # identical statistics.
@@ -32,8 +31,7 @@ stats
 a: (1, .)
 c: (2, .)
 .
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 57B, cached 57B, read-time 0s)), (points: (count 2, key-bytes 2B, value-bytes 2B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 2 times (2 internal); blocks: 57B cached; points: 2 (2B keys, 2B values)
 
 build ext2
 set d@10 d10
@@ -63,18 +61,13 @@ next
 stats
 ----
 c: (2, .)
-stats: (interface (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 0), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 57B, cached 57B, read-time 0s)), (points: (count 1, key-bytes 1B, value-bytes 1B, tombstoned 0)))
+stats: seeked 1 times (1 internal); stepped 0 times (0 internal); blocks: 57B cached; points: 1 (1B keys, 1B values)
 d@10: (d10, .)
 d@9: (d9, .)
-stats: (interface (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 2), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 157B, cached 147B, read-time 0s)), (points: (count 3, key-bytes 8B, value-bytes 6B, tombstoned 0)), (separated: (count 1, bytes 2B, fetched 2B)))
+stats: seeked 1 times (1 internal); stepped 2 times (2 internal); blocks: 147B cached, 10B not cached (read time: 0s); points: 3 (8B keys, 6B values); separated: 1 (2B, 2B fetched)
 d@8: (d8, .)
-stats: (interface (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 3), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 157B, cached 147B, read-time 0s)), (points: (count 4, key-bytes 11B, value-bytes 8B, tombstoned 0)), (separated: (count 2, bytes 4B, fetched 4B)))
+stats: seeked 1 times (1 internal); stepped 3 times (3 internal); blocks: 147B cached, 10B not cached (read time: 0s); points: 4 (11B keys, 8B values); separated: 2 (4B, 4B fetched)
 e@20: (e20, .)
-stats: (interface (dir, seek, step): (fwd, 1, 4), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 4), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 157B, cached 147B, read-time 0s)), (points: (count 5, key-bytes 15B, value-bytes 11B, tombstoned 0)), (separated: (count 2, bytes 4B, fetched 4B)))
+stats: seeked 1 times (1 internal); stepped 4 times (4 internal); blocks: 147B cached, 10B not cached (read time: 0s); points: 5 (15B keys, 11B values); separated: 2 (4B, 4B fetched)
 e@18: (e18, .)
-stats: (interface (dir, seek, step): (fwd, 1, 5), (rev, 0, 0)), (internal (dir, seek, step): (fwd, 1, 5), (rev, 0, 0)),
-(internal-stats: (block-bytes: (total 157B, cached 147B, read-time 0s)), (points: (count 6, key-bytes 19B, value-bytes 13B, tombstoned 0)), (separated: (count 3, bytes 7B, fetched 7B)))
+stats: seeked 1 times (1 internal); stepped 5 times (5 internal); blocks: 147B cached, 10B not cached (read time: 0s); points: 6 (19B keys, 13B values); separated: 3 (7B, 7B fetched)