From: Tomasz Kamiński Date: Tue, 28 Jul 2026 14:43:49 +0000 (+0200) Subject: libstdc++: Resolve UNTIL save adjustment at tzdb loading time [PR116110] X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ce285dde2110f453fdbbd89fbb2f85a4d039705d;p=thirdparty%2Fgcc.git 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 Signed-off-by: Tomasz Kamiński --- diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc index 6fe3c6cfee6..e358b778e2d 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();