Re: [PATCH v2] libstdc++: Skip locale in chrono operator<< for integer seconds precision
Tomasz Kaminski <[email protected]> Tue, 4 Aug 2026 08:33:59 +0200
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CAKvuMXBqCDeq4OngaH1xAJJCyV=jLmoeU5_PYXYAkNHQyh39pA@mail.gmail.com> |
Hi Anlai, Patch was merged, thanks again for doing it. Regards, Tomasz On Mon, Aug 3, 2026 at 6:17 PM Jonathan Wakely <[email protected]> wrote: > > > On Mon, 27 Jul 2026 at 08:41, Tomasz Kaminski <[email protected]> wrote: > >> Thanks this looks good to me. I will handle merging it once approved, >> with adjustments to the changelog listed below: >> > > OK with those changes, thanks. > > > > >> >> On Mon, Jul 27, 2026 at 5:29 AM Anlai Lu <[email protected]> wrote: >> >>> When _Duration uses integer seconds precision (period::den == 1, >>> not floating-point), time_point formatting has no sub-second >>> digits and therefore no locale-dependent components. Add >>> __detail::__chrono_write_time that conditionally skips the locale >>> argument for integer-second time_points, eliminating the >>> format_to_n locale overload and the basic_format_context >>> locale member initialization. >>> >>> Also add [[__gnu__::__always_inline__]] to >>> __formatter_chrono::_M_subsecs to mitigate a small mixed-TU >>> inlining regression. >>> >>> libstdc++-v3/ChangeLog: >>> >>> * include/bits/chrono_io.h >>> (__detail::__chrono_write_time): New function that conditionally >>> skips locale for integer-second time_points. >>> (__formatter_chrono::_M_subsecs): Add __always_inline__. >>> (operator<< for hh_mm_ss): Use if constexpr to skip locale >>> for integer-second durations. >>> (operator<< for sys_time, utc_time, tai_time, gps_time, >>> file_time, local_time, zoned_time): Use __chrono_write_time. >>> >> Changed it to: >> * include/bits/chrono_io.h (__detail::__chrono_write_time): >> New function that conditionally skips locale for >> integer-second >> time_points. >> (__formatter_chrono::_M_subsecs): Add __always_inline__. >> (operator<<(basic_ostream<...>, const hh_mm_ss<_Duration>&)): >> Use if constexpr to skip locale for integer-second durations. >> (operator<<(basic_ostream<...>, const zoned_time<_Duration>&)) >> (operator<<(basic_ostream<...>, const sys_time<_Duration>&)) >> (operator<<(basic_ostream<...>, const utc_time<_Duration>&)) >> (operator<<(basic_ostream<...>, const tai_time<_Duration>&)) >> (operator<<(basic_ostream<...>, const file_time<_Duration>&)) >> (operator<<(basic_ostream<...>, const >> local_time<_Duration>&)): >> Use __chrono_write_time. >> (operator<<(basic_ostream<...>, const sys_days<_Duration>&)): >> Remove trailing semicolon. >> >> >>> Suggested-by: Tomasz Kamiński <[email protected]> >>> >> Changed the above to: >> Reviewed-by: Tomasz Kamiński <[email protected]> >> >>> Signed-off-by: Anlai Lu <[email protected]> >>> --- >>> Performance data (Xeon, -O2, core pinned, turbo off): >>> >>> den==1 types instructions branches >>> --------------- ------------ -------- >>> sys_time_s -5.0% -11.3% >>> utc_time_s -5.0% -11.3% >>> tai_time_s -5.0% -11.3% >>> gps_time_s -5.0% -11.3% >>> file_time_s -5.0% -11.3% >>> local_time_s -5.1% -11.3% >>> zoned_time_s -2.8% -5.3% >>> hh_mm_ss_s -7.1% -15.7% >>> >>> den!=1: >>> sys_time_ms +0.3% +0.6% >>> utc_time_ms +0.3% +0.6% >>> local_time_ms +0.3% +0.6% >>> hh_mm_ss_ms +0.4% +0.7% >>> >>> --- >>> libstdc++-v3/include/bits/chrono_io.h | 44 +++++++++++++++++++++------ >>> 1 file changed, 34 insertions(+), 10 deletions(-) >>> >>> diff --git a/libstdc++-v3/include/bits/chrono_io.h >>> b/libstdc++-v3/include/bits/chrono_io.h >>> index c5170368f..2cbd61ccd 100644 >>> --- a/libstdc++-v3/include/bits/chrono_io.h >>> +++ b/libstdc++-v3/include/bits/chrono_io.h >>> @@ -1656,6 +1656,7 @@ namespace __format >>> } >>> >>> template<typename _OutIter, typename _FormatContext> >>> + [[__gnu__::__always_inline__]] >>> _OutIter >>> _M_subsecs(const _ChronoData<_CharT>& __t, _OutIter __out, >>> _FormatContext& __ctx) const >>> @@ -3635,6 +3636,23 @@ namespace __detail >>> return std::__ostream_insert(__os, __s.data(), __s.size()); >>> } >>> >>> + // Wrapper around __chrono_write that skips locale for >>> + // integer-second time_points. >>> + template<size_t _BufSize, typename _TimePoint, typename _CharT, >>> + typename _Traits> >>> + [[__gnu__::__always_inline__]] >>> + inline basic_ostream<_CharT, _Traits>& >>> + __chrono_write_time(basic_ostream<_CharT, _Traits>& __os, >>> + const _TimePoint& __tp) >>> + { >>> + using _Duration = typename _TimePoint::duration; >>> + if constexpr (!treat_as_floating_point_v<typename _Duration::rep> >>> + && _Duration::period::den == 1) >>> + return __chrono_write<_BufSize>(__os, __tp); >>> + else >>> + return __chrono_write<_BufSize>(__os, __tp, __os.getloc()); >>> + } >>> + >>> } // namespace __detail >>> /// @endcond >>> >>> @@ -3740,7 +3758,7 @@ namespace __detail >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const weekday_last& __wdl) >>> { return __detail::__chrono_write<128>(__os, __wdl, __os.getloc()); >>> } >>> - >>> + >>> template<typename _CharT, typename _Traits> >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, const month_day& >>> __md) >>> @@ -3846,7 +3864,13 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const hh_mm_ss<_Duration>& __hms) >>> - { return __detail::__chrono_write<64>(__os, __hms, __os.getloc()); } >>> + { >>> + if constexpr (!treat_as_floating_point_v<typename _Duration::rep> >>> + && _Duration::period::den == 1) >>> + return __detail::__chrono_write<64>(__os, __hms); >>> + else >>> + return __detail::__chrono_write<64>(__os, __hms, __os.getloc()); >>> + } >>> >>> #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI >>> /// Writes a sys_info object to an ostream in an unspecified format. >>> @@ -3866,7 +3890,7 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const zoned_time<_Duration, _TimeZonePtr>& __t) >>> - { return __detail::__chrono_write<128>(__os, __t, __os.getloc()); } >>> + { return __detail::__chrono_write_time<128>(__os, __t); } >>> #endif >>> >>> template<typename _CharT, typename _Traits, typename _Duration> >>> @@ -3875,12 +3899,12 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const sys_time<_Duration>& __tp) >>> - { return __detail::__chrono_write<64>(__os, __tp, __os.getloc()); } >>> + { return __detail::__chrono_write_time<64>(__os, __tp); } >>> >>> template<typename _CharT, typename _Traits> >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, const sys_days& >>> __dp) >>> - { return __detail::__chrono_write<32>(__os, __dp); }; >>> + { return __detail::__chrono_write<32>(__os, __dp); } >>> >>> template<typename _CharT, typename _Traits, typename _Duration, >>> typename _Alloc = allocator<_CharT>> >>> @@ -3914,7 +3938,7 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const utc_time<_Duration>& __t) >>> - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } >>> + { return __detail::__chrono_write_time<64>(__os, __t); } >>> >>> template<typename _CharT, typename _Traits, typename _Duration, >>> typename _Alloc = allocator<_CharT>> >>> @@ -3946,7 +3970,7 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const tai_time<_Duration>& __t) >>> - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } >>> + { return __detail::__chrono_write_time<64>(__os, __t); } >>> >>> template<typename _CharT, typename _Traits, typename _Duration, >>> typename _Alloc = allocator<_CharT>> >>> @@ -3982,7 +4006,7 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const gps_time<_Duration>& __t) >>> - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } >>> + { return __detail::__chrono_write_time<64>(__os, __t); } >>> >>> template<typename _CharT, typename _Traits, typename _Duration, >>> typename _Alloc = allocator<_CharT>> >>> @@ -4017,7 +4041,7 @@ namespace __detail >>> inline basic_ostream<_CharT, _Traits>& >>> operator<<(basic_ostream<_CharT, _Traits>& __os, >>> const file_time<_Duration>& __t) >>> - { return __detail::__chrono_write<64>(__os, __t, __os.getloc()); } >>> + { return __detail::__chrono_write_time<64>(__os, __t); } >>> >>> template<typename _CharT, typename _Traits, typename _Duration, >>> typename _Alloc = allocator<_CharT>> >>> @@ -4040,7 +4064,7 @@ namespace __detail >>> // _GLIBCXX_RESOLVE_LIB_DEFECTS >>> // 4257. Stream insertion for chrono::local_time should be >>> constrained >>> requires requires(const sys_time<_Duration>& __st) { __os << __st; } >>> - { return __detail::__chrono_write<64>(__os, __lt, __os.getloc()); } >>> + { return __detail::__chrono_write_time<64>(__os, __lt); } >>> >>> template<typename _CharT, typename _Traits, typename _Duration, >>> typename _Alloc = allocator<_CharT>> >>> -- >>> 2.34.1 >>> >>>