From ad9b39a76231a85e663783244a7a826b34c8468a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 6 Feb 2026 17:05:30 -0600 Subject: [PATCH] scripts: csv.py: Added saturate function This is useful for enforcing an upper-bound on fracs based on their total component. Technically possible via decomposing + min + recomposing, but... Well which one do you think is easier? - saturate(x) - frac(min(max(int(x), 0), total(x)), total(x)) And this assumes x is easily available and not some other expr (though chaining csv.py could work around that). --- The motivation for this was `make bench-widths`, where one read benchmark could ruin the entire column due to introducing infinities. Now: make bench # (squished a bit) probe readed progged erased b_wt_seq+w 1.0/1.0 (100.0%) 31.7/256.0 (12.4%) 4096.0/4096.0 (100.0%) b_wt_random+w 1.0/1.0 (100.0%) 15.3/256.0 (6.0%) 4096.0/4096.0 (100.0%) b_wt_logging+w 1.0/1.0 (100.0%) 15.4/256.0 (6.0%) 4096.0/4096.0 (100.0%) b_wt_many+w 1.0/1.0 (100.0%) 16.1/256.0 (6.3%) 4096.0/4096.0 (100.0%) b_rt_seq+r 1.0/1.0 (100.0%) 256.0/256.0 (100.0%) 4096.0/4096.0 (100.0%) b_rt_random+r 1.0/1.0 (100.0%) 256.0/256.0 (100.0%) 4096.0/4096.0 (100.0%) b_rt_many+r 1.0/1.0 (100.0%) 256.0/256.0 (100.0%) 4096.0/4096.0 (100.0%) TOTAL 1.0/1.0 (100.0%) 149.0/256.0 (58.2%) 4096.0/4096.0 (100.0%) # ^- notably not infinity --- Makefile | 12 ++++++------ scripts/csv.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index f4dad5f6..350c100c 100644 --- a/Makefile +++ b/Makefile @@ -693,24 +693,24 @@ bench-widths: $(BENCH_CSV) write,stat,read \ -bprobe='%(case)s+%(probe)s' \ -Fi='min(enumerate())' \ - -freaded="avg(ffrac( \ + -freaded="avg(saturate(ffrac( \ float(bench_readed)/float(bench_reads), \ max(1, $$( \ ./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) \ --list-implicit-defines \ - | sed -n 's/^READ_WIDTH=\(.*\)/\1/p'))))" \ - -fprogged="avg(ffrac( \ + | sed -n 's/^READ_WIDTH=\(.*\)/\1/p')))))" \ + -fprogged="avg(saturate(ffrac( \ float(bench_progged)/float(bench_progs), \ max(1, $$( \ ./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) \ --list-implicit-defines \ - | sed -n 's/^PROG_WIDTH=\(.*\)/\1/p'))))" \ - -ferased="avg(ffrac( \ + | sed -n 's/^PROG_WIDTH=\(.*\)/\1/p')))))" \ + -ferased="avg(saturate(ffrac( \ float(bench_erased)/float(bench_erases), \ max(1, $$( \ ./scripts/bench.py -R$(BENCH_RUNNER) $(BENCHFLAGS) \ --list-implicit-defines \ - | sed -n 's/^ERASE_WIDTH=\(.*\)/\1/p'))))" \ + | sed -n 's/^ERASE_WIDTH=\(.*\)/\1/p')))))" \ $(SUMMARYFLAGS)) ## Show heap/stack/disk usage diff --git a/scripts/csv.py b/scripts/csv.py index 3c0dbdda..392c77a6 100755 --- a/scripts/csv.py +++ b/scripts/csv.py @@ -1099,6 +1099,18 @@ class CsvExpr: else: return v.b + @func('saturate', 'a') + class Saturate(Expr): + """Limit to total part of a fraction""" + def eval(self, fields={}, state=None): + v = self.a.eval(fields, state) + if not hasattr(v, '__frac__'): + return v + elif isinstance(v, CsvFrac): + return CsvFrac(min(max(v.a, CsvInt(0)), v.b), v.b) + elif isinstance(v, CsvFfrac): + return CsvFfrac(min(max(v.a, CsvFloat(0)), v.b), v.b) + @func('abs', 'a') class Abs(Expr): """Absolute value"""