From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from sonic306-22.consmr.mail.ne1.yahoo.com (sonic306-22.consmr.mail.ne1.yahoo.com [66.163.189.84]) by sourceware.org (Postfix) with ESMTPS id A3975385500A for ; Wed, 14 Jul 2021 21:54:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A3975385500A X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1626299695; bh=bYfqYrkVMUXyGB4MI2ziRxfZIyC8mCrHTLMprmNuy2W=; h=X-Sonic-MF:From:Subject:Date:To:From:Subject; b=ttb09qxxsyRnh6abVzlVSHoIR3sB1jD5M2aOlywWPLKcDPJktePLerVh8zJ0YFQr/IsPV5svTx8A62V/rpb4JJkljpEZSZM6evM9t4q8QyN7qIMg86YU0HE+cTGU+qudQouwnN27CIh+afEwamJytpRXlm/Z4iw784p1XSSyO/2kyvd3oVolgbYS7t3ubpTOglihkRNhvvI3J9+wB0kpowVkt26gOFHYiW8oAn1/s+RaZQqUbor+SRjyl9LZtda0lHwykGShX7PyAXynDWrRkW/D6EpWpDNgpNnydhNVSrl3VjPxs2rCJAwNpWpQtS8loMCOHK3q+dOpHnBdlp87/Q== X-YMail-OSG: Zu0fNf8VM1lRBUClnCGXbStCpNGGBKWsaRO.p.lPQwHUxj_we.7djX6kbWUYJvH LaX51J7lGEKn0gsG2bE.JJ8zGaz0bzhfzbldv_ymM_QFsEzeeVSIhxtJikaNv3yGA4DMsZs85fp8 MKdhoChdj_MuxW6yO5VhQcSexO19ANGhvVmcVpeO3b3VziZF91KW.4NwBKlao4cz0.InIamaVOkY mYc71K5cPkADXbd_NgOd.vXHjTIiz5XqzGu0b3Ki1Lw_2DNnmjlA.RFYMQ8Z9Qbyk6fZiYEZ9m6C P.Fk0pN1Qd2FVkpZ.urg1MY2s6UUTqzEGMeui6FJJeptL_S4c3P_uQX7rlYDOeh304mpG.78LnQK L5dzKVOxAcVvL83HHSgm3xdAdQRCuhHn6bHDUSArls0Tbc3XmQrEI6Y0YdEGF7PdhyFWjrGfHA6d JrkDgLoy9UDdV_U6anJY87av3i3M0Gryf8FHPTtT.BcTyv455BIrr00A5OKXnBNTb3Yv3im9rIkW yW2mnr3EMbxR2wqp0LYKEkbEEfYE4X_KmNxgUOPvGLPaYO3KjnUEMUWcPicjh.U6yQAubID9OsT. ZU7lqrNvRheSGsCjEOBuEC9Ay_eE9Ff2dJDsJG0LcIfphdF4M.0Y_fiFhgaE0BQ_D6EjmSJ8n_WW mFbgN.boagsWSwo9QvqbhuGy0irQM4hXh9SOvvI0etSOP1zfDpXPZNcUnSISwEDEXVFTHlQcP_Ya nPvSTpKybrZUtWFvD6gtFSjwN0YNwCwZ56XJ1VdZ4PGDXaR6qNwMU6QmXGNRCmGB6XmeOcRsmnX0 TmiEuUqXjHjzA.ic2V4hb1X_BRP3BsnbsJYOfDp78X_Fk98MJaBC9o1MreUuYQottDUYrFPRlYff gF0jMNldKUGaoJ5XrwBl5Y00DK6zzwevRZKOZUKVjNTHc28sdtpRlCVPlOShTXHnek.RMbnvf3Gp vKNp3zJ4NpvBSFVwbysafCMYgR3PsiiDToM_KNsaGS3Ow9wvzqxelm7hH4Ikcr0un5TizAQlXO1. uc3iA6VQ0UBKCD8GPFO7OMOhRn0dYoG0xtxWbqJWrBSd57hgTkVk7oxr2bLVPjhIfaAdY.PAz3Bk 3_4xQmwR4F4rDH.CNkrIDEpsZENQeZoNN9YtkmemTaVc.17QM3X1iAE9r1_Ew1OtElEglsX15W7B A1QGOPL.J1XId08LWd9S5mC4K5Zs9DdqvWRIgoEKe_MZD0XLlxntPe8fX7acBFQ.p1eHiw0pgRYy KW9.xMJBAJSczFFM2pus_ZGNVyW7ZmujIIfGpMT3XtHE7pEKEFVtbIHJh0ziDmKVBpFk6TVSztDo F5lKDpUUFj4BDt1iXyxQjazpc5QERkzSTyxPhSocN9MpUyAnXksqYXek8HaouWWiKd2ZOFlG1nOr 1jkailylVVE9zMdUwy51Oq6euldcsBABBHSkQIuL6OI5CGI3X6_71HDCYQnKIkvnQ9axRWQIEutB OpXiPNP_2ZkSMQD4BVf_H3dGQxQUseEJrSf_SOr0PLTajKO0sd7GbpeFUSY7fl.743X8zarTaVEM 9MqdpaPVvuEvx9DGSZRQ3YsSKP5MCK8.sSPkbsFmP9LWrft.UhvoAxJmhPf34oj9WwfHI1bP1lrs ICgsIxdN2zhyq04sG7gzZJdEP_OK_m2u6Nm7ciWiO3iX4ho_30mt1Jqx7XKICM1r7nhXoxyHvEat Y36Yk61BikzzidD8bhlaUAiEv6zt89bX3Lniawr9xVoVlguisFTCtQs00Q36M9RWIlfGoqYt4iuJ BOMfb_Z0ietdT9BXOyvr6sKX5oW65ywOJM_b.joSvLD2c0JVVQrBg5y6grfVUrBOFtyhWN15jL3E Nm3ztjy5KzEMUDypZrM5euXwKDxuSo28NsenQQJ.lzxtobQdhs_3XrMdh58LNhKycGKu_WMnXri1 TTWNU8caGJAhCq_B__wRedheIjF3y7DZY0rrO1OifyV1_RXC2HhFUTN9cUY.3btMnfMCYaxVZVlv i2tK5.SDf1_a5kzgOdGyZSCS.d.cLZFPmLnfOASndAlTRj2TRgS3_tIXGcsUfHOibc5uahTNGNSU 8QsNWdpJPeM7lNFkU5JquHGr3iBED8lRJEusf2vYMqh0b2aQOdvh7Xip9xtcFUjIJr8rdqZZ_XtM h1UhQa.fAavSB4MGEkNYHn9E40E9InE4gfXrzvJocSCrQnPOxgy3.FHbG8PHYgu5bb8H_HOlbldw NTYSp7Pgldi1cg_qSVX9vSAUx35crv6y1k0tg82lcQjGaJyZFY8PslkSsmn7jQ0cOfNAB_9KEDNF 6AC6gN3Go2fTVq0GIkr9V8VZkCyQGgsD2jUkqOOwGmq9qYiwrnbHMYmWw_vE.UAjY03RwGBgRiAs tQf4urFSf3D3yk0FiT.InJbxe06HPXMqzBdXXpEccyU6yd5r.U_3L451AzGGDlcXV5xgk7z1mbDl ye49fvLVBHA13xB48DEAd9hstWhNRE_dz3mLwGiu2seZLcvLmQt53SH2FYUCBDu8W2geL5bSRGdD FWmqwckCc4kJBmWrE5xPRthKvLckPJ0h00Be7EJsxB_Rp.K4tIl.TyHnA7rti X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic306.consmr.mail.ne1.yahoo.com with HTTP; Wed, 14 Jul 2021 21:54:55 +0000 Received: by kubenode550.mail-prod1.omega.ir2.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 96e944afda669502a465ccf11b099f95; Wed, 14 Jul 2021 21:54:54 +0000 (UTC) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: =?utf-8?Q?Dietmar_K=C3=BChl?= Mime-Version: 1.0 (1.0) Subject: Re: ostream::operator<<() and sputn() Date: Wed, 14 Jul 2021 22:54:52 +0100 Message-Id: References: Cc: Lewis Hyatt , libstdc++ In-Reply-To: To: Jonathan Wakely X-Mailer: iPad Mail (18F72) X-Spam-Status: No, score=-0.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Jul 2021 21:54:58 -0000 Hello, Of course, you could detect whether the user did specialize basic_streambuf:= the default implementation can use a special member name, let=E2=80=99s say= , __not_specialized, which the user cannot write in a portable program and, h= ence, in the user=E2=80=99s specialization. Detecting that could opt into an= enhanced code path. I=E2=80=99m not recommending to use such an implementat= ion. When I implemented my own version of IOStreams I used a few special app= roaches, notably a segmented iterator optimization for std::[io]streambuf_it= erator with a bit more direct access to the streambuf=E2=80=99s buffer. For a= ctually buffered streams these things can yield a substantial performance bo= ost. There is some penalty for non-buffered (well, single character buffered= ) stream buffers, though. Making changes to the streams while maintaining ABI compatibility is probabl= y not quite worth the trouble, though. Thanks, Dietmar > On 14 Jul 2021, at 22:31, Jonathan Wakely via Libstdc++ wrote: >=20 > =EF=BB=BFOn Wed, 14 Jul 2021 at 22:26, Lewis Hyatt via Libstdc++ > wrote: >>=20 >> Hello- >>=20 >> I noticed that libstdc++'s implementation of ostream::operator<<() prefer= s >> to call sputn() on the underlying streambuf for all char, char*, and stri= ng >> output operations, including single characters, rather than manipulate th= e >> buffer directly. I am curious why it works this way, it feels perhaps >> suboptimal to me because sputn() is mandated to call the virtual function= >> xsputn() on every call, while e.g. sputc() simply manipulates the buffer a= nd >> only needs a virtual call when the buffer is full. I always thought that t= he >> buffer abstraction and the resulting avoidance of virtual calls for the >> majority of operations was the main point of streambuf's design, and that= >> sputn() was meant for cases when the output would be large enough to >> overflow the buffer anyway, if it may be possible to skip the buffer and >> flush directly instead? >>=20 >> It seems to me that for most typical use cases, xsputn() is still going t= o >> want to use the buffer if the output fits into it; libstdc++ does this in= >> basic_filebuf, for example. So then it would seem to be beneficial to try= >> the buffer prior to making the virtual function call, instead of after --= >> especially because the typical char instantiation of __ostream_insert tha= t >> makes this call for operator<<() is hidden inside the .so, and is not >> inlined or eligible for devirtualization optimizations. >>=20 >> FWIW, here is a small test case. >>=20 >> --------- >> #include >> #include >> #include >> #include >> #include >> #include >> using namespace std; >>=20 >> int main() { >> constexpr size_t N =3D 500000000; >> string s(N, 'x'); >>=20 >> ofstream of{"/dev/null"}; >> ostringstream os; >> ostream* streams[] =3D {&of, &os}; >> mt19937 rng{random_device{}()}; >>=20 >> const auto timed_run =3D [&](const char* label, auto&& callback) { >> const auto t1 =3D chrono::steady_clock::now(); >> for(char c: s) callback(*streams[rng() % 2], c); >> const auto t2 =3D chrono::steady_clock::now(); >> cout << label << " took: " >> << chrono::duration(t2-t1).count() >> << " seconds" << endl; >> }; >>=20 >> timed_run("insert with put()", [](ostream& o, char c) {o.put(c);}); >> timed_run("insert with op<< ", [](ostream& o, char c) {o << c;}); >> } >> --------- >>=20 >> This is what I get with the current trunk: >> --------- >> insert with put() took: 6.12152 seconds >> insert with op<< took: 13.4437 seconds >> --------- >>=20 >> And this is what I get with the attached patch: >> --------- >> insert with put() took: 6.08313 seconds >> insert with op<< took: 8.24565 seconds >> --------- >>=20 >> So the overhead of calling operator<< vs calling put() was reduced by mor= e >> than 3X. >>=20 >> The prototype patch calls an internal alternate to sputn(), which tries t= he >> buffer prior to calling xsputn(). >=20 > This won't work if a user provides an explicit specialization of > basic_streambuf. std::basic_ostream > will still try to call your new function, but it won't be present in > the user's specialization, so will fail to compile. The basic_ostream > primary template can only use the standard API of basic_streambuf. The > std::basic_ostream specialization can use non-standard members > of std::basic_streambuf because we know users can't specialize > that.