Hi Tomasz, Thanks for the updated patches.
I re-ran the benchmarks on the updated patches (x86_64, -O2, core pinned, BABA interleaved, vs trunk): scenario (vs trunk) 4 B 16 B 64 B 256 B 1024 B 4096 B fmt_to 1.14x 1.83x 4.14x 17.40x 54.26x 118.79x fmt_to_n (notrunc) 1.12x 1.78x 4.90x 16.13x 54.61x 119.57x fmt_to_noputarea 1.27x 2.03x 5.78x 19.86x 21.36x 26.49x fmt_to_filebuf 1.19x 1.98x 5.26x 12.21x 19.29x 20.71x fmt_to_append 1.19x 1.87x 4.40x 13.37x 32.46x 47.73x fmt_to_scanner 1.13x 1.09x 1.08x 1.07x 1.08x 1.07x print (control) 1.01x 0.99x 0.99x 1.00x 0.97x 0.99x string (control) 1.00x 1.10x 1.00x 0.99x 1.04x 1.01x Perf stat for the primary fmt_to path: len instr% cycles% b_IPC a_IPC 4 85.8% 87.9% 2.76 2.69 16 64.5% 54.2% 2.24 2.66 64 32.8% 19.5% 1.60 2.69 256 11.7% 5.7% 1.36 2.76 1024 4.0% 2.3% 1.33 2.37 4096 1.8% 0.9% 1.33 2.65 Compared with the numbers from Jul 16: 4096B is unchanged (121.22x -> 118.79x, within noise), 256B improved (10.98x -> 17.40x). > On Aug 11, 2026, at 16:42, Tomasz Kaminski <[email protected]> wrote: > > > > On Thu, Jul 16, 2026 at 2:04 PM Anlai Lu <[email protected] <mailto:[email protected]>> > wrote: >> This series replaces per-character sputc() with bulk sputn() and >> zero-copy put-area writes when formatting to ostreambuf_iterator. >> Patch 2 adds a _Streambuf_sink that writes directly to a streambuf; >> patch 3 specializes _Iter_sink to use it; patch 4 uses _Streambuf_sink >> in std::print; patch 1 adds tests. >> >> Performance: >> >> fmt_to (ostreambuf_iter) 4 B 16 B 64 B 256 B 1024 B 4096 B >> v3: 0.97x 1.61x 4.15x 10.98x 51.97x 121.22x >> >> print (uses _Streambuf_sink, per [ostream.formatted.print]): >> 4 B 16 B 64 B 256 B 1024 B 4096 B >> before (ns/op): 87 114 112 118 190 286 >> after (ns/op): 78 78 77 86 82 134 >> ratio: 1.12x 1.47x 1.46x 1.37x 2.33x 2.14x >> >> string / fmt_to_scanner unchanged (controls). > Hi, > I have posted an updated version of first 3 patches (see my comments on > fourth one, explaining why it is non-conforming, and needs a paper to allow > taht optimization). Would you mind redoing your tests on the updated patches, > as I do not have access to them? >> >> Changes in v3 >> ============== >> (Items marked with [R] were suggested by Tomasz Kaminski.) >> >> - Extracted protected _M_flush(span) from _M_overflow so that both >> _M_overflow and _M_finish share the same write path, and the >> _Iter_sink specialization reuses it too. [R] >> - Added _M_write_failed flag and _M_discarding() override to >> _Streambuf_sink, so the format engine stops output early after a >> write failure. [R] >> - Changed _M_max from __diff_t to size_t with _S_no_limit sentinel. [R] >> - Error propagation to the iterator moved to _Iter_sink::_M_finish >> (checked just before returning std::move), so _M_overflow no longer >> touches _M_out. >> - Used _Streambuf_sink directly in vprint_nonunicode (patch 4), >> replacing the _Str_sink + __ostream_write two-phase approach. >> - Added _M_set_failed() to ostreambuf_iterator for the iterator's >> error propagation path. >> - Added try/catch in _M_flush to handle sputn I/O exceptions without >> letting them propagate as vformat exceptions. Per >> [ostream.formatted.print]/(4.2), vformat exceptions propagate without >> badbit; I/O exceptions from sputn are not vformat exceptions and >> are converted to _M_write_failed, then reported as badbit per (4.4). >> - _M_finish() now ref-qualified (&&) on all sinks for consistency; >> the print path uses std::move to call it. [R] >> - Extracted _M_limit(span) helper in the _Iter_sink specialization for >> shared counting/truncation between _M_overflow and _M_finish; >> _M_finish now calls _M_flush directly, skipping unnecessary buffer >> restoration. [R] >> >> Not applied >> ============ >> 1. Destructor flush [R] >> Flush in destruction runs after the error check in print, so it >> cannot help report I/O errors. And no other sink flushes in its >> destructor. >> >> 2. _M_bump override [R] >> The default advances _M_next within the current span; commit >> happens via _M_flush. A comment explains this. >> >> Anlai Lu (4): >> libstdc++: Add tests for format_to with ostreambuf_iterator >> libstdc++: Add _Streambuf_sink for direct streambuf formatting >> libstdc++: Specialize _Iter_sink for ostreambuf_iterator >> libstdc++: Optimize std::print using _Streambuf_sink >> >> libstdc++-v3/include/bits/ostream_print.h | 12 +- >> .../include/bits/streambuf_iterator.h | 11 + >> libstdc++-v3/include/std/format | 199 ++++++++++++++ >> libstdc++-v3/include/std/streambuf | 4 + >> .../format/functions/format_to_ostreambuf.cc | 244 ++++++++++++++++++ >> 5 files changed, 463 insertions(+), 7 deletions(-) >> create mode 100644 >> libstdc++-v3/testsuite/std/format/functions/format_to_ostreambuf.cc >> >> base-commit: a0591d86bd2be838e30c132481a0b15a6ba1e112 >> >> -- >> 2.34.1
