Re: [PATCH v2] libstdc++: Skip locale in chrono operator<< for integer seconds precision
Jonathan Wakely <[email protected]> Mon, 3 Aug 2026 17:16:31 +0100
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CACb0b4naGg_7ocj1sd19n-6wvP+P9eB-JUO4WskJGZadV7SAsQ@mail.gmail.com> |
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 >> >>