[gcc r17-2787] libstdc++: Resolve UNTIL save adjustment at tzdb loading time [PR116110]

Tomasz Kaminski tkaminsk@gcc.gnu.org
Wed Jul 29 11:34:03 GMT 2026


https://gcc.gnu.org/g:ce285dde2110f453fdbbd89fbb2f85a4d039705d

commit r17-2787-gce285dde2110f453fdbbd89fbb2f85a4d039705d
Author: Tomasz Kamiński <tkaminsk@redhat.com>
Date:   Tue Jul 28 16:43:49 2026 +0200

    libstdc++: Resolve UNTIL save adjustment at tzdb loading time [PR116110]
    
    This patch moves the save calculation (ZoneInfo::calc_save) to database
    loading code (reload_tzdb) instead of applying it on demand when zone
    is queried (time_zone::_M_get_sys_info). This eliminates the performance
    impact on non-first calls (that return the cached result), caused by
    iterator adjustment checks.
    
    Local performance test indicate a 10% cost (30ns to 33ns on average) for
    cached queries with on-demand implementation (after r17-2466-g020e02fcf28),
    combined with huge swings on time on first calls. This patch leads 200ms
    increase (1.95s to 2.15s) on time of reload_tzdb, that happens only during
    initial load (and later explicit reload).
    
    As we need two bits of state (expanded or until_pending), I have decided
    to keep the four value m_state enum.
    
            PR libstdc++/116110
    
    libstdc++-v3/ChangeLog:
    
            * src/c++20/tzdb.cc (time_zone::_M_get_sys_info): Remove
            ZoneInfo::calc_save invocation and related iterator adjustment.
            (chrono::reload_tzdb): Calculate save (invoke calc_save) for
            all infos on all zones.
    
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>

Diff:
---
 libstdc++-v3/src/c++20/tzdb.cc | 25 +++++++------------------
 1 file changed, 7 insertions(+), 18 deletions(-)

diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
index 6fe3c6cfee64..e358b778e2d6 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -1069,35 +1069,19 @@ namespace std::chrono
     // Find the transition info for the time point.
     auto i = ranges::upper_bound(infos, tp, ranges::less{}, &ZoneInfo::until);
 
-    // Perform the comparison on save adjusted until values (if needed)
-    // Assume that applying the save will not change relative order of
-    // ZoneInfo objects.
-    if (i != infos.begin() && i[-1].calc_save(node->rules) && (i[-1].until() > tp))
-      --i;
-    else if (i != infos.end() && i->calc_save(node->rules) && (i->until() <= tp))
-      ++i;
-
     if (i == infos.end())
       {
 	if (infos.empty())
 	  __throw_runtime_error("std::chrono::time_zone::get_info: invalid data");
-	(--i)->calc_save(node->rules);
-	tp = i->until();
+	tp = (--i)->until();
       }
-    else // Guarantee that i->until() is correct
-      i->calc_save(node->rules);
-
 
     sys_info info;
 
     if (i == infos.begin())
       info.begin = sys_days(year::min()/January/1);
     else
-      {
-	ZoneInfo& prev = i[-1];
-	prev.calc_save(node->rules);
-	info.begin = prev.until();
-      }
+      info.begin = i[-1].until();
 
     if (i->to(info)) // We already know a sys_info for this time.
       return info;
@@ -2050,6 +2034,11 @@ constinit tzdb_list::_Node::NumLeapSeconds tzdb_list::_Node::num_leap_seconds;
       return lhs.save < rhs.save;
     });
 
+    // Calculate the SAVE value at UNTIL, and adjust it if necessary.
+    for (time_zone& tz : node->db.zones)
+      for (ZoneInfo& info : tz._M_impl->infos)
+	info.calc_save(node->rules);
+
     return Node::_S_replace_head(std::move(head), std::move(node));
 #else
     __throw_disabled();


More information about the Libstdc++-cvs mailing list