On Fri, Jul 24, 2026 at 4:40 PM Anlai Lu <[email protected]> wrote:

>
>
> > On Jul 24, 2026, at 22:27, 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 an
> > overload of __detail::__chrono_write that conditionally skips
> > the locale argument, eliminating the format_to_n locale overload
> > and the basic_format_context locale member initialization.
> >
> > libstdc++-v3/ChangeLog:
> >
> > * include/bits/chrono_io.h
> > (__detail::__chrono_write): New overload skipping locale
> > for integer-second durations.
> > (operator<< for hh_mm_ss, sys_time, utc_time, tai_time,
> > gps_time, file_time, local_time, zoned_time): Use it.
> >
> > Suggested-by: Tomasz Kamiński <[email protected]>
> > Signed-off-by: Anlai Lu <[email protected]>
> > ---
> >
> > Performance data (Xeon, -O2, core pinned, turbo off, 50M iters):
> >
> >  den==1 types     instructions   branches
> >  ---------------  ------------   --------
> >  sys_time_s         -4.2%         -9.6%
> >  utc_time_s         -3.8%         -8.7%
> >  tai_time_s         -4.2%         -9.6%
> >  gps_time_s         -4.2%         -9.6%
> >  file_time_s        -4.2%         -9.6%
> >  local_time_s       -4.2%         -9.6%
> >  zoned_time_s       -2.4%         -4.6%
> >  hh_mm_ss_s         -6.0%        -13.6%
> >
> >  den!=1 (control):
> >  sys_time_ms        +1.0%         +1.1%
> >  utc_time_ms        +1.0%         +1.1%
> >  local_time_ms      +1.0%         +1.1%
> >  hh_mm_ss_ms        +1.3%         +1.4%
> >
> > The den==1 improvement comes from compile-time removal of the
> > format_to_n locale overload and basic_format_context locale
> > member.  The den!=1 +1.0% is a known measurement artifact from
> Quick follow-up.  Not a measurement artifact, a codegen artifact.
>
> The mechanism is a GCC codegen side effect from mixed-TU compilation:
> when den==1 and den!=1 instantiations coexist in the same translation
> unit, GCC's inlining heuristics may shift slightly, de-inlining
> __formatter_chrono::_M_subsecs (and a few other helpers).
>
It may be worth adding __gnu__::__always_inline__ on this particular
function.

> This adds call/return overhead for those functions.  Isolated
> single-type TUs are indeed byte-identical to the baseline.
> The regression can be reduced from +1.0% to +0.3% with
> [[gnu::always_inline]] on _M_subsecs.  This patch does not include that
> change.
>
> > mixing 12 time_point instantiations in one translation unit;
> > isolated single-type tests show zero difference.
> >
> >
> > libstdc++-v3/include/bits/chrono_io.h | 35 +++++++++++++++++++--------
> > 1 file changed, 25 insertions(+), 10 deletions(-)
> >
> > diff --git a/libstdc++-v3/include/bits/chrono_io.h
> b/libstdc++-v3/include/bits/chrono_io.h
> > index c5170368f..fa40290a8 100644
> > --- a/libstdc++-v3/include/bits/chrono_io.h
> > +++ b/libstdc++-v3/include/bits/chrono_io.h
> > @@ -3635,6 +3635,21 @@ namespace __detail
> >       return std::__ostream_insert(__os, __s.data(), __s.size());
> >     }
> >
> > +  // Overload of __chrono_write that conditionally skips locale for
> > +  // integer-second time_points, hh_mm_ss, and zoned_time.
> > +  template<size_t _BufSize, typename _Duration, typename _CharT,
> > +   typename _Traits, typename _Tp>
> > +    inline basic_ostream<_CharT, _Traits>&
> > +    __chrono_write(basic_ostream<_CharT, _Traits>& __os,
> > +      const _Tp& __val)
> > +    {
> > +      if constexpr (!treat_as_floating_point_v<typename _Duration::rep>
> > +    && _Duration::period::den == 1)
> > + return __chrono_write<_BufSize>(__os, __val);
> > +      else
> > + return __chrono_write<_BufSize>(__os, __val, __os.getloc());
> > +    }
> > +
> > } // namespace __detail
> > /// @endcond
> >
> > @@ -3740,7 +3755,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 +3861,7 @@ 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()); }
> > +    { return __detail::__chrono_write<64, _Duration>(__os, __hms); }
> >
> > #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
> >   /// Writes a sys_info object to an ostream in an unspecified format.
> > @@ -3866,7 +3881,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<128, _Duration>(__os, __t); }
> > #endif
> >
> >   template<typename _CharT, typename _Traits, typename _Duration>
> > @@ -3875,12 +3890,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<64, _Duration>(__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 +3929,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<64, _Duration>(__os, __t); }
> >
> >   template<typename _CharT, typename _Traits, typename _Duration,
> >   typename _Alloc = allocator<_CharT>>
> > @@ -3946,7 +3961,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<64, _Duration>(__os, __t); }
> >
> >   template<typename _CharT, typename _Traits, typename _Duration,
> >   typename _Alloc = allocator<_CharT>>
> > @@ -3982,7 +3997,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<64, _Duration>(__os, __t); }
> >
> >   template<typename _CharT, typename _Traits, typename _Duration,
> >   typename _Alloc = allocator<_CharT>>
> > @@ -4017,7 +4032,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<64, _Duration>(__os, __t); }
> >
> >   template<typename _CharT, typename _Traits, typename _Duration,
> >   typename _Alloc = allocator<_CharT>>
> > @@ -4040,7 +4055,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<64, _Duration>(__os, __lt); }
> >
> >   template<typename _CharT, typename _Traits, typename _Duration,
> >   typename _Alloc = allocator<_CharT>>
> > --
> > 2.34.1
>
>

Reply via email to